From b45a0ebe6ed8f06ff91da4d2f9ee2907e2e0ac58 Mon Sep 17 00:00:00 2001 From: RogueException Date: Sun, 8 May 2016 01:31:07 -0300 Subject: [PATCH] 1.0 REST Preview 2 --- Discord.Net.sln | 53 +- NuGet.config | 8 - global.json | 6 - src/Discord.Net/{ => API}/CDN.cs | 4 +- src/Discord.Net/API/Common/Channel.cs | 4 +- .../Common/{Unconfirmed => }/Connection.cs | 14 +- src/Discord.Net/API/Common/Guild.cs | 2 + src/Discord.Net/API/Common/GuildMember.cs | 2 + .../API/Common/{Unconfirmed => }/Overwrite.cs | 0 .../API/Common/Unconfirmed/ExtendedGuild.cs | 23 - .../API/Common/Unconfirmed/ExtendedMember.cs | 12 - .../API/Common/Unconfirmed/MemberPresence.cs | 14 - .../Common/Unconfirmed/MemberPresenceGame.cs | 10 - .../API/Common/Unconfirmed/MemberReference.cs | 12 - .../Common/Unconfirmed/MessageReference.cs | 14 - .../API/Common/Unconfirmed/RoleReference.cs | 12 - src/Discord.Net/API/Common/UserGuild.cs | 2 + .../VoiceRegion.cs} | 14 +- .../MemberVoiceState.cs => VoiceState.cs} | 28 +- src/Discord.Net/API/DiscordRawClient.cs | 785 ++++++++++++++++++ src/Discord.Net/API/GatewaySocket/OpCode.cs | 26 - .../Unconfirmed/Commands/Heartbeat.cs | 12 - .../Unconfirmed/Commands/Identify.cs | 23 - .../Unconfirmed/Commands/RequestMembers.cs | 18 - .../Unconfirmed/Commands/Resume.cs | 16 - .../Unconfirmed/Commands/UpdateStatus.cs | 22 - .../Unconfirmed/Commands/UpdateVoice.cs | 20 - .../Unconfirmed/Events/ChannelCreate.cs | 4 - .../Unconfirmed/Events/ChannelDelete.cs | 4 - .../Unconfirmed/Events/ChannelUpdate.cs | 4 - .../Unconfirmed/Events/GuildBanAdd.cs | 4 - .../Unconfirmed/Events/GuildBanRemove.cs | 4 - .../Unconfirmed/Events/GuildCreate.cs | 4 - .../Unconfirmed/Events/GuildDelete.cs | 4 - .../Unconfirmed/Events/GuildMemberAdd.cs | 4 - .../Unconfirmed/Events/GuildMemberRemove.cs | 4 - .../Unconfirmed/Events/GuildMemberUpdate.cs | 4 - .../Unconfirmed/Events/GuildMembersChunk.cs | 12 - .../Unconfirmed/Events/GuildRoleCreate.cs | 12 - .../Unconfirmed/Events/GuildRoleDelete.cs | 4 - .../Unconfirmed/Events/GuildRoleUpdate.cs | 12 - .../Unconfirmed/Events/GuildUpdate.cs | 4 - .../Unconfirmed/Events/MessageAck.cs | 4 - .../Unconfirmed/Events/MessageCreate.cs | 4 - .../Unconfirmed/Events/MessageDelete.cs | 4 - .../Unconfirmed/Events/MessageUpdate.cs | 4 - .../Unconfirmed/Events/PresenceUpdate.cs | 4 - .../GatewaySocket/Unconfirmed/Events/Ready.cs | 40 - .../Unconfirmed/Events/Resumed.cs | 10 - .../Unconfirmed/Events/TypingStart.cs | 14 - .../Unconfirmed/Events/UserUpdate.cs | 4 - .../Unconfirmed/Events/VoiceServerUpdate.cs | 14 - .../Unconfirmed/Events/VoiceStateUpdate.cs | 4 - src/Discord.Net/API/IWebSocketMessage.cs | 28 - src/Discord.Net/API/Rest/AcceptInvite.cs | 18 - src/Discord.Net/API/Rest/AckMessage.cs | 20 - src/Discord.Net/API/Rest/BeginGuildPrune.cs | 23 - .../API/Rest/CreateChannelInvite.cs | 29 - .../API/Rest/CreateChannelInviteParams.cs | 16 + src/Discord.Net/API/Rest/CreateDMChannel.cs | 16 - .../API/Rest/CreateDMChannelParams.cs | 10 + src/Discord.Net/API/Rest/CreateGuildBan.cs | 24 - .../API/Rest/CreateGuildBanParams.cs | 10 + .../API/Rest/CreateGuildChannel.cs | 27 - .../API/Rest/CreateGuildChannelParams.cs | 14 + .../API/Rest/CreateGuildIntegration.cs | 25 - .../API/Rest/CreateGuildIntegrationParams.cs | 12 + .../{CreateGuild.cs => CreateGuildParams.cs} | 10 +- src/Discord.Net/API/Rest/CreateGuildRole.cs | 18 - src/Discord.Net/API/Rest/CreateMessage.cs | 27 - .../API/Rest/CreateMessageParams.cs | 14 + src/Discord.Net/API/Rest/DeleteChannel.cs | 18 - .../API/Rest/DeleteChannelPermission.cs | 20 - src/Discord.Net/API/Rest/DeleteGuild.cs | 18 - .../API/Rest/DeleteGuildIntegration.cs | 20 - src/Discord.Net/API/Rest/DeleteGuildRole.cs | 20 - src/Discord.Net/API/Rest/DeleteInvite.cs | 18 - src/Discord.Net/API/Rest/DeleteMessage.cs | 20 - .../API/Rest/DeleteMessagesParam.cs | 11 + src/Discord.Net/API/Rest/GetChannel.cs | 18 - src/Discord.Net/API/Rest/GetChannelInvites.cs | 20 - .../API/Rest/GetChannelMessages.cs | 34 - .../API/Rest/GetChannelMessagesParams.cs | 9 + src/Discord.Net/API/Rest/GetCurrentUser.cs | 11 - .../API/Rest/GetCurrentUserConnections.cs | 11 - src/Discord.Net/API/Rest/GetCurrentUserDMs.cs | 11 - .../API/Rest/GetCurrentUserGuilds.cs | 11 - src/Discord.Net/API/Rest/GetGateway.cs | 18 - .../GetGatewayResponse.cs} | 4 +- 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 - .../API/Rest/GetGuildIntegrations.cs | 18 - src/Discord.Net/API/Rest/GetGuildInvites.cs | 18 - src/Discord.Net/API/Rest/GetGuildMember.cs | 20 - .../API/Rest/GetGuildMembersParams.cs | 8 + .../API/Rest/GetGuildPruneCount.cs | 29 - .../API/Rest/GetGuildPruneCountResponse.cs | 10 + src/Discord.Net/API/Rest/GetGuildRoles.cs | 18 - .../API/Rest/GetGuildVoiceRegions.cs | 18 - src/Discord.Net/API/Rest/GetInvite.cs | 18 - src/Discord.Net/API/Rest/GetUser.cs | 18 - src/Discord.Net/API/Rest/GuildPruneParams.cs | 10 + src/Discord.Net/API/Rest/LeaveGuild.cs | 18 - src/Discord.Net/API/Rest/ListGuildMembers.cs | 24 - .../API/Rest/ModifyChannelPermission.cs | 27 - .../Rest/ModifyChannelPermissionsParams.cs | 12 + ...rentUser.cs => ModifyCurrentUserParams.cs} | 10 +- .../API/Rest/ModifyGuildChannel.cs | 25 - .../API/Rest/ModifyGuildChannelParams.cs | 12 + .../API/Rest/ModifyGuildChannels.cs | 22 - .../API/Rest/ModifyGuildChannelsParams.cs | 12 + src/Discord.Net/API/Rest/ModifyGuildEmbed.cs | 25 - .../API/Rest/ModifyGuildEmbedParams.cs | 13 + .../API/Rest/ModifyGuildIntegration.cs | 29 - .../API/Rest/ModifyGuildIntegrationParams.cs | 14 + src/Discord.Net/API/Rest/ModifyGuildMember.cs | 31 - .../API/Rest/ModifyGuildMemberParams.cs | 17 + .../{ModifyGuild.cs => ModifyGuildParams.cs} | 23 +- src/Discord.Net/API/Rest/ModifyGuildRole.cs | 32 - .../API/Rest/ModifyGuildRoleParams.cs | 18 + src/Discord.Net/API/Rest/ModifyGuildRoles.cs | 21 - .../API/Rest/ModifyGuildRolesParams.cs | 10 + src/Discord.Net/API/Rest/ModifyMessage.cs | 25 - .../API/Rest/ModifyMessageParams.cs | 10 + src/Discord.Net/API/Rest/ModifyTextChannel.cs | 16 - .../API/Rest/ModifyTextChannelParams.cs | 10 + .../API/Rest/ModifyVoiceChannel.cs | 16 - .../API/Rest/ModifyVoiceChannelParams.cs | 10 + src/Discord.Net/API/Rest/QueryUser.cs | 19 - src/Discord.Net/API/Rest/RemoveGuildBan.cs | 20 - src/Discord.Net/API/Rest/RemoveGuildMember.cs | 20 - .../API/Rest/SyncGuildIntegration.cs | 21 - .../API/Rest/TriggerTypingIndicator.cs | 18 - src/Discord.Net/API/Rest/UploadFile.cs | 35 - src/Discord.Net/API/Rest/UploadFileParams.cs | 24 + src/Discord.Net/API/VoiceSocket/OpCode.cs | 18 - .../Unconfirmed/Commands/Heartbeat.cs | 10 - .../Unconfirmed/Commands/Identify.cs | 19 - .../Unconfirmed/Commands/SelectProtocol.cs | 28 - .../Unconfirmed/Commands/SetSpeaking.cs | 15 - .../VoiceSocket/Unconfirmed/Events/Ready.cs | 16 - .../Unconfirmed/Events/SessionDescription.cs | 12 - .../Unconfirmed/Events/Speaking.cs | 14 - src/Discord.Net/Discord.Net.Net45.csproj | 303 ------- .../Discord.Net.Net45.project.json | 12 - .../Discord.Net.Net45.project.lock.json | 88 -- src/Discord.Net/Discord.Net.csproj | 209 +++++ src/Discord.Net/Discord.Net.xproj | 21 - src/Discord.Net/DiscordClient.cs | 341 -------- src/Discord.Net/DiscordConfig.cs | 53 +- src/Discord.Net/DiscordRestClient.cs | 256 ++++++ src/Discord.Net/DiscordSocketClient.cs | 176 ---- .../Entities/Channels/DMChannel.cs | 97 --- .../Entities/Channels/GuildChannel.cs | 129 --- src/Discord.Net/Entities/Channels/IChannel.cs | 17 - .../Entities/Channels/IMessageChannel.cs | 30 - .../Entities/Channels/TextChannel.cs | 67 -- .../Entities/Channels/VoiceChannel.cs | 39 - .../Common/Channels}/ChannelType.cs | 0 .../Entities/Common/Channels/IChannel.cs | 13 + .../Entities/Common/Channels/IDMChannel.cs | 13 + .../Entities/Common/Channels/IGuildChannel.cs | 51 ++ .../Common/Channels/IMessageChannel.cs | 29 + .../Entities/Common/Channels/ITextChannel.cs | 15 + .../Entities/Common/Channels/IVoiceChannel.cs | 15 + .../Entities/{ => Common/Guilds}/Emoji.cs | 11 +- .../Entities/Common/Guilds/IGuild.cs | 94 +++ .../Entities/Common/Guilds/IGuildEmbed.cs | 8 + .../Common/Guilds/IGuildIntegration.cs | 21 + .../Common/Guilds/IIntegrationAccount.cs | 7 + .../Entities/Common/Guilds/IUserGuild.cs | 14 + .../Entities/Common/Guilds/IVoiceRegion.cs | 16 + src/Discord.Net/Entities/Common/IDeletable.cs | 10 + src/Discord.Net/Entities/Common/IEntity.cs | 8 + .../Entities/{ => Common}/IMentionable.cs | 1 + .../Entities/Common/ISnowflakeEntity.cs | 10 + .../Entities/Common/IUpdateable.cs | 10 + .../Entities/Common/Invites/IGuildInvite.cs | 19 + .../Entities/Common/Invites/IInvite.cs | 24 + .../Entities/Common/Invites/IPublicInvite.cs | 10 + .../{ => Common/Messages}/Attachment.cs | 0 .../Common/Messages/Direction.cs} | 2 +- .../Entities/{ => Common/Messages}/Embed.cs | 0 .../{ => Common/Messages}/EmbedProvider.cs | 0 .../{ => Common/Messages}/EmbedThumbnail.cs | 0 .../Entities/Common/Messages/IMessage.cs | 42 + .../Common/Permissions/ChannelPermission.cs | 36 + .../Common/Permissions/ChannelPermissions.cs | 136 +++ .../Common/Permissions/GuildPermission.cs} | 13 +- .../Common/Permissions/GuildPermissions.cs | 145 ++++ .../{ => Common}/Permissions/Overwrite.cs | 0 .../Permissions/OverwritePermissions.cs | 135 +++ .../Common/Permissions}/PermValue.cs | 0 .../Common/Permissions}/PermissionTarget.cs | 0 .../Common/Permissions/PermissionUtilities.cs | 87 ++ .../Entities/{ => Common/Roles}/Color.cs | 2 +- .../Entities/Common/Roles/IRole.cs | 32 + .../Entities/Common/Users/IConnection.cs | 14 + .../Entities/Common/Users/IDMUser.cs | 8 + .../Entities/Common/Users/IGuildUser.cs | 40 + .../Entities/Common/Users/ISelfUser.cs | 16 + .../Entities/Common/Users/IUser.cs | 23 + .../Users/IVoiceState.cs.old} | 2 +- .../Common/Users}/UserStatus.cs | 0 src/Discord.Net/Entities/Guild.cs | 383 --------- .../Entities/Helpers/InviteManager.cs | 8 - .../Entities/Helpers/MentionHelper.cs | 111 --- .../Entities/Helpers/MessageManager.cs | 174 ---- .../Entities/Helpers/PermissionManager.cs | 289 ------- .../Entities/Helpers/PermissionsHelper.cs | 61 -- src/Discord.Net/Entities/IEntity.cs | 19 - .../Entities/Invites/GuildInvite.cs | 71 -- src/Discord.Net/Entities/Invites/IInvite.cs | 20 - src/Discord.Net/Entities/Invites/Invite.cs | 48 -- .../Entities/Invites/InviteChannel.cs | 16 - .../Entities/Invites/InviteGuild.cs | 16 - src/Discord.Net/Entities/Message.cs | 139 ---- .../Permissions/ChannelPermissions.cs | 122 --- .../Entities/Permissions/GuildPermissions.cs | 119 --- .../Permissions/OverwritePermissions.cs | 113 --- .../Entities/Rest/Channels/DMChannel.cs | 146 ++++ .../Entities/Rest/Channels/GuildChannel.cs | 173 ++++ .../Entities/Rest/Channels/TextChannel.cs | 119 +++ .../Entities/Rest/Channels/VoiceChannel.cs | 45 + src/Discord.Net/Entities/Rest/Guilds/Guild.cs | 365 ++++++++ .../Entities/Rest/Guilds/GuildEmbed.cs | 32 + .../Entities/Rest/Guilds/GuildIntegration.cs | 85 ++ .../Rest/Guilds/IntegrationAccount.cs | 11 + .../Entities/Rest/Guilds/UserGUild.cs | 55 ++ .../Entities/Rest/Guilds/VoiceRegion.cs | 30 + .../Entities/Rest/Helper/PermissionHelper.cs | 64 ++ .../Entities/Rest/Invites/GuildInvite.cs | 52 ++ .../Entities/Rest/Invites/Invite.cs | 48 ++ .../Entities/Rest/Invites/PublicInvite.cs | 39 + src/Discord.Net/Entities/Rest/Message.cs | 140 ++++ src/Discord.Net/Entities/Rest/Role.cs | 80 ++ .../Entities/Rest/Users/Connection.cs | 27 + src/Discord.Net/Entities/Rest/Users/DMUser.cs | 20 + .../Entities/Rest/Users/GuildUser.cs | 97 +++ .../Entities/Rest/Users/PublicUser.cs | 15 + .../Entities/Rest/Users/SelfUser.cs | 48 ++ src/Discord.Net/Entities/Rest/Users/User.cs | 66 ++ src/Discord.Net/Entities/Role.cs | 85 -- src/Discord.Net/Entities/Users/DMUser.cs | 42 - src/Discord.Net/Entities/Users/GlobalUser.cs | 55 -- src/Discord.Net/Entities/Users/GuildUser.cs | 81 -- src/Discord.Net/Entities/Users/IUser.cs | 14 - src/Discord.Net/Entities/Users/SelfUser.cs | 23 - src/Discord.Net/Entities/VoiceRegion.cs | 60 -- src/Discord.Net/Enums/ConnectionState.cs | 10 - src/Discord.Net/Events/ChannelEventArgs.cs | 14 - .../Events/ChannelUpdatedEventArgs.cs | 14 - .../Events/CurrentUserEventArgs.cs | 14 - .../Events/CurrentUserUpdatedEventArgs.cs | 14 - .../Events/DisconnectedEventArgs.cs | 16 - src/Discord.Net/Events/GuildEventArgs.cs | 14 - .../Events/GuildUpdatedEventArgs.cs | 14 - src/Discord.Net/Events/LogMessageEventArgs.cs | 2 +- src/Discord.Net/Events/MessageEventArgs.cs | 14 - .../Events/MessageUpdatedEventArgs.cs | 14 - src/Discord.Net/Events/RoleEventArgs.cs | 14 - .../Events/RoleUpdatedEventArgs.cs | 14 - .../Events/SentRequestEventArgs.cs | 20 + src/Discord.Net/Events/TypingEventArgs.cs | 16 - src/Discord.Net/Events/UserEventArgs.cs | 14 - .../Events/UserUpdatedEventArgs.cs | 14 - .../Events/VoiceChannelEventArgs.cs | 14 - src/Discord.Net/Format.cs | 105 --- src/Discord.Net/Helpers/DateTimeHelper.cs | 17 + src/Discord.Net/Helpers/EventExtensions.cs | 13 + src/Discord.Net/Helpers/MentionHelper.cs | 163 ++++ src/Discord.Net/IDiscordClient.cs | 37 + src/Discord.Net/InternalExtensions.cs | 22 - src/Discord.Net/{Enums => }/LogSeverity.cs | 0 src/Discord.Net/Logging/ILogger.cs | 32 + src/Discord.Net/Logging/LogManager.cs | 62 +- src/Discord.Net/Logging/Logger.cs | 2 +- src/Discord.Net/MessageQueue.cs | 287 ------- .../ChannelTypeConverter.cs | 2 +- .../ImageConverter.cs | 2 +- .../NullableUInt64Converter.cs | 2 +- .../PermissionTargetConverter.cs | 2 +- .../StringEntityConverter.cs | 2 +- .../UInt64ArrayConverter.cs | 2 +- .../UInt64Converter.cs | 2 +- .../UInt64EntityConverter.cs | 2 +- .../UserStatusConverter.cs | 2 +- ...aultRestEngine.cs => DefaultRestClient.cs} | 50 +- src/Discord.Net/Net/Rest/IMessageQueue.cs | 7 + src/Discord.Net/Net/Rest/IRestClient.cs | 14 + src/Discord.Net/Net/Rest/IRestEngine.cs | 14 - src/Discord.Net/Net/Rest/IRestRequest.cs | 27 - src/Discord.Net/Net/Rest/MultipartFile.cs | 16 + src/Discord.Net/Net/Rest/RestClient.cs | 98 --- .../Net/Rest/RestClientProvider.cs | 2 +- src/Discord.Net/Net/Rest/RestParameter.cs | 19 - .../Net/Rest/SentRequestEventArgs.cs | 16 - .../Net/WebSockets/BinaryMessageEventArgs.cs | 11 - .../Net/WebSockets/DefaultWebSocketEngine.cs | 180 ---- .../Net/WebSockets/GatewaySocket.cs | 42 - .../Net/WebSockets/IWebSocketEngine.cs | 18 - .../Net/WebSockets/TextMessageEventArgs.cs | 11 - src/Discord.Net/Net/WebSockets/WebSocket.cs | 27 - .../Net/WebSockets/WebSocketEventEventArgs.cs | 11 - .../Net/WebSockets/WebSocketProvider.cs | 6 - src/Discord.Net/Properties/AssemblyInfo.cs | 14 +- src/Discord.Net/TaskHelper.cs | 18 - src/Discord.Net/TokenType.cs | 9 + src/Discord.Net/project.json | 37 +- 311 files changed, 4905 insertions(+), 6549 deletions(-) delete mode 100644 NuGet.config delete mode 100644 global.json rename src/Discord.Net/{ => API}/CDN.cs (94%) rename src/Discord.Net/API/Common/{Unconfirmed => }/Connection.cs (81%) rename src/Discord.Net/API/Common/{Unconfirmed => }/Overwrite.cs (100%) delete mode 100644 src/Discord.Net/API/Common/Unconfirmed/ExtendedGuild.cs delete mode 100644 src/Discord.Net/API/Common/Unconfirmed/ExtendedMember.cs delete mode 100644 src/Discord.Net/API/Common/Unconfirmed/MemberPresence.cs delete mode 100644 src/Discord.Net/API/Common/Unconfirmed/MemberPresenceGame.cs delete mode 100644 src/Discord.Net/API/Common/Unconfirmed/MemberReference.cs delete mode 100644 src/Discord.Net/API/Common/Unconfirmed/MessageReference.cs delete mode 100644 src/Discord.Net/API/Common/Unconfirmed/RoleReference.cs rename src/Discord.Net/API/{Rest/GetVoiceRegions.cs => Common/VoiceRegion.cs} (56%) rename src/Discord.Net/API/Common/{Unconfirmed/MemberVoiceState.cs => VoiceState.cs} (51%) create mode 100644 src/Discord.Net/API/DiscordRawClient.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/OpCode.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Heartbeat.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Identify.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/RequestMembers.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Resume.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/UpdateStatus.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/UpdateVoice.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelCreate.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelDelete.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelUpdate.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildBanAdd.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildBanRemove.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildCreate.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildDelete.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberAdd.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberRemove.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberUpdate.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMembersChunk.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleCreate.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleDelete.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleUpdate.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildUpdate.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageAck.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageCreate.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageDelete.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageUpdate.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/PresenceUpdate.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Ready.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Resumed.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/TypingStart.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/UserUpdate.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/VoiceServerUpdate.cs delete mode 100644 src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/VoiceStateUpdate.cs delete mode 100644 src/Discord.Net/API/IWebSocketMessage.cs delete mode 100644 src/Discord.Net/API/Rest/AcceptInvite.cs delete mode 100644 src/Discord.Net/API/Rest/AckMessage.cs delete mode 100644 src/Discord.Net/API/Rest/BeginGuildPrune.cs delete mode 100644 src/Discord.Net/API/Rest/CreateChannelInvite.cs create mode 100644 src/Discord.Net/API/Rest/CreateChannelInviteParams.cs delete mode 100644 src/Discord.Net/API/Rest/CreateDMChannel.cs create mode 100644 src/Discord.Net/API/Rest/CreateDMChannelParams.cs delete mode 100644 src/Discord.Net/API/Rest/CreateGuildBan.cs create mode 100644 src/Discord.Net/API/Rest/CreateGuildBanParams.cs delete mode 100644 src/Discord.Net/API/Rest/CreateGuildChannel.cs create mode 100644 src/Discord.Net/API/Rest/CreateGuildChannelParams.cs delete mode 100644 src/Discord.Net/API/Rest/CreateGuildIntegration.cs create mode 100644 src/Discord.Net/API/Rest/CreateGuildIntegrationParams.cs rename src/Discord.Net/API/Rest/{CreateGuild.cs => CreateGuildParams.cs} (52%) delete mode 100644 src/Discord.Net/API/Rest/CreateGuildRole.cs delete mode 100644 src/Discord.Net/API/Rest/CreateMessage.cs create mode 100644 src/Discord.Net/API/Rest/CreateMessageParams.cs delete mode 100644 src/Discord.Net/API/Rest/DeleteChannel.cs delete mode 100644 src/Discord.Net/API/Rest/DeleteChannelPermission.cs delete mode 100644 src/Discord.Net/API/Rest/DeleteGuild.cs delete mode 100644 src/Discord.Net/API/Rest/DeleteGuildIntegration.cs delete mode 100644 src/Discord.Net/API/Rest/DeleteGuildRole.cs delete mode 100644 src/Discord.Net/API/Rest/DeleteInvite.cs delete mode 100644 src/Discord.Net/API/Rest/DeleteMessage.cs create mode 100644 src/Discord.Net/API/Rest/DeleteMessagesParam.cs delete mode 100644 src/Discord.Net/API/Rest/GetChannel.cs delete mode 100644 src/Discord.Net/API/Rest/GetChannelInvites.cs delete mode 100644 src/Discord.Net/API/Rest/GetChannelMessages.cs create mode 100644 src/Discord.Net/API/Rest/GetChannelMessagesParams.cs delete mode 100644 src/Discord.Net/API/Rest/GetCurrentUser.cs delete mode 100644 src/Discord.Net/API/Rest/GetCurrentUserConnections.cs delete mode 100644 src/Discord.Net/API/Rest/GetCurrentUserDMs.cs delete mode 100644 src/Discord.Net/API/Rest/GetCurrentUserGuilds.cs delete mode 100644 src/Discord.Net/API/Rest/GetGateway.cs rename src/Discord.Net/API/{GatewaySocket/Unconfirmed/Events/Redirect.cs => Rest/GetGatewayResponse.cs} (62%) delete mode 100644 src/Discord.Net/API/Rest/GetGuild.cs delete mode 100644 src/Discord.Net/API/Rest/GetGuildBans.cs delete mode 100644 src/Discord.Net/API/Rest/GetGuildChannels.cs delete mode 100644 src/Discord.Net/API/Rest/GetGuildEmbed.cs delete mode 100644 src/Discord.Net/API/Rest/GetGuildIntegrations.cs delete mode 100644 src/Discord.Net/API/Rest/GetGuildInvites.cs delete mode 100644 src/Discord.Net/API/Rest/GetGuildMember.cs create mode 100644 src/Discord.Net/API/Rest/GetGuildMembersParams.cs delete mode 100644 src/Discord.Net/API/Rest/GetGuildPruneCount.cs create mode 100644 src/Discord.Net/API/Rest/GetGuildPruneCountResponse.cs delete mode 100644 src/Discord.Net/API/Rest/GetGuildRoles.cs delete mode 100644 src/Discord.Net/API/Rest/GetGuildVoiceRegions.cs delete mode 100644 src/Discord.Net/API/Rest/GetInvite.cs delete mode 100644 src/Discord.Net/API/Rest/GetUser.cs create mode 100644 src/Discord.Net/API/Rest/GuildPruneParams.cs delete mode 100644 src/Discord.Net/API/Rest/LeaveGuild.cs delete mode 100644 src/Discord.Net/API/Rest/ListGuildMembers.cs delete mode 100644 src/Discord.Net/API/Rest/ModifyChannelPermission.cs create mode 100644 src/Discord.Net/API/Rest/ModifyChannelPermissionsParams.cs rename src/Discord.Net/API/Rest/{ModifyCurrentUser.cs => ModifyCurrentUserParams.cs} (62%) delete mode 100644 src/Discord.Net/API/Rest/ModifyGuildChannel.cs create mode 100644 src/Discord.Net/API/Rest/ModifyGuildChannelParams.cs delete mode 100644 src/Discord.Net/API/Rest/ModifyGuildChannels.cs create mode 100644 src/Discord.Net/API/Rest/ModifyGuildChannelsParams.cs delete mode 100644 src/Discord.Net/API/Rest/ModifyGuildEmbed.cs create mode 100644 src/Discord.Net/API/Rest/ModifyGuildEmbedParams.cs delete mode 100644 src/Discord.Net/API/Rest/ModifyGuildIntegration.cs create mode 100644 src/Discord.Net/API/Rest/ModifyGuildIntegrationParams.cs delete mode 100644 src/Discord.Net/API/Rest/ModifyGuildMember.cs create mode 100644 src/Discord.Net/API/Rest/ModifyGuildMemberParams.cs rename src/Discord.Net/API/Rest/{ModifyGuild.cs => ModifyGuildParams.cs} (56%) delete mode 100644 src/Discord.Net/API/Rest/ModifyGuildRole.cs create mode 100644 src/Discord.Net/API/Rest/ModifyGuildRoleParams.cs delete mode 100644 src/Discord.Net/API/Rest/ModifyGuildRoles.cs create mode 100644 src/Discord.Net/API/Rest/ModifyGuildRolesParams.cs delete mode 100644 src/Discord.Net/API/Rest/ModifyMessage.cs create mode 100644 src/Discord.Net/API/Rest/ModifyMessageParams.cs delete mode 100644 src/Discord.Net/API/Rest/ModifyTextChannel.cs create mode 100644 src/Discord.Net/API/Rest/ModifyTextChannelParams.cs delete mode 100644 src/Discord.Net/API/Rest/ModifyVoiceChannel.cs create mode 100644 src/Discord.Net/API/Rest/ModifyVoiceChannelParams.cs delete mode 100644 src/Discord.Net/API/Rest/QueryUser.cs delete mode 100644 src/Discord.Net/API/Rest/RemoveGuildBan.cs delete mode 100644 src/Discord.Net/API/Rest/RemoveGuildMember.cs delete mode 100644 src/Discord.Net/API/Rest/SyncGuildIntegration.cs delete mode 100644 src/Discord.Net/API/Rest/TriggerTypingIndicator.cs delete mode 100644 src/Discord.Net/API/Rest/UploadFile.cs create mode 100644 src/Discord.Net/API/Rest/UploadFileParams.cs delete mode 100644 src/Discord.Net/API/VoiceSocket/OpCode.cs delete mode 100644 src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/Heartbeat.cs delete mode 100644 src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/Identify.cs delete mode 100644 src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/SelectProtocol.cs delete mode 100644 src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/SetSpeaking.cs delete mode 100644 src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/Ready.cs delete mode 100644 src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/SessionDescription.cs delete mode 100644 src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/Speaking.cs delete mode 100644 src/Discord.Net/Discord.Net.Net45.csproj delete mode 100644 src/Discord.Net/Discord.Net.Net45.project.json delete mode 100644 src/Discord.Net/Discord.Net.Net45.project.lock.json create mode 100644 src/Discord.Net/Discord.Net.csproj delete mode 100644 src/Discord.Net/Discord.Net.xproj delete mode 100644 src/Discord.Net/DiscordClient.cs create mode 100644 src/Discord.Net/DiscordRestClient.cs delete mode 100644 src/Discord.Net/DiscordSocketClient.cs delete mode 100644 src/Discord.Net/Entities/Channels/DMChannel.cs delete mode 100644 src/Discord.Net/Entities/Channels/GuildChannel.cs delete mode 100644 src/Discord.Net/Entities/Channels/IChannel.cs delete mode 100644 src/Discord.Net/Entities/Channels/IMessageChannel.cs delete mode 100644 src/Discord.Net/Entities/Channels/TextChannel.cs delete mode 100644 src/Discord.Net/Entities/Channels/VoiceChannel.cs rename src/Discord.Net/{Enums => Entities/Common/Channels}/ChannelType.cs (100%) create mode 100644 src/Discord.Net/Entities/Common/Channels/IChannel.cs create mode 100644 src/Discord.Net/Entities/Common/Channels/IDMChannel.cs create mode 100644 src/Discord.Net/Entities/Common/Channels/IGuildChannel.cs create mode 100644 src/Discord.Net/Entities/Common/Channels/IMessageChannel.cs create mode 100644 src/Discord.Net/Entities/Common/Channels/ITextChannel.cs create mode 100644 src/Discord.Net/Entities/Common/Channels/IVoiceChannel.cs rename src/Discord.Net/Entities/{ => Common/Guilds}/Emoji.cs (62%) create mode 100644 src/Discord.Net/Entities/Common/Guilds/IGuild.cs create mode 100644 src/Discord.Net/Entities/Common/Guilds/IGuildEmbed.cs create mode 100644 src/Discord.Net/Entities/Common/Guilds/IGuildIntegration.cs create mode 100644 src/Discord.Net/Entities/Common/Guilds/IIntegrationAccount.cs create mode 100644 src/Discord.Net/Entities/Common/Guilds/IUserGuild.cs create mode 100644 src/Discord.Net/Entities/Common/Guilds/IVoiceRegion.cs create mode 100644 src/Discord.Net/Entities/Common/IDeletable.cs create mode 100644 src/Discord.Net/Entities/Common/IEntity.cs rename src/Discord.Net/Entities/{ => Common}/IMentionable.cs (53%) create mode 100644 src/Discord.Net/Entities/Common/ISnowflakeEntity.cs create mode 100644 src/Discord.Net/Entities/Common/IUpdateable.cs create mode 100644 src/Discord.Net/Entities/Common/Invites/IGuildInvite.cs create mode 100644 src/Discord.Net/Entities/Common/Invites/IInvite.cs create mode 100644 src/Discord.Net/Entities/Common/Invites/IPublicInvite.cs rename src/Discord.Net/Entities/{ => Common/Messages}/Attachment.cs (100%) rename src/Discord.Net/{Enums/Relative.cs => Entities/Common/Messages/Direction.cs} (72%) rename src/Discord.Net/Entities/{ => Common/Messages}/Embed.cs (100%) rename src/Discord.Net/Entities/{ => Common/Messages}/EmbedProvider.cs (100%) rename src/Discord.Net/Entities/{ => Common/Messages}/EmbedThumbnail.cs (100%) create mode 100644 src/Discord.Net/Entities/Common/Messages/IMessage.cs create mode 100644 src/Discord.Net/Entities/Common/Permissions/ChannelPermission.cs create mode 100644 src/Discord.Net/Entities/Common/Permissions/ChannelPermissions.cs rename src/Discord.Net/{Enums/PermissionBits.cs => Entities/Common/Permissions/GuildPermission.cs} (70%) create mode 100644 src/Discord.Net/Entities/Common/Permissions/GuildPermissions.cs rename src/Discord.Net/Entities/{ => Common}/Permissions/Overwrite.cs (100%) create mode 100644 src/Discord.Net/Entities/Common/Permissions/OverwritePermissions.cs rename src/Discord.Net/{Enums => Entities/Common/Permissions}/PermValue.cs (100%) rename src/Discord.Net/{Enums => Entities/Common/Permissions}/PermissionTarget.cs (100%) create mode 100644 src/Discord.Net/Entities/Common/Permissions/PermissionUtilities.cs rename src/Discord.Net/Entities/{ => Common/Roles}/Color.cs (97%) create mode 100644 src/Discord.Net/Entities/Common/Roles/IRole.cs create mode 100644 src/Discord.Net/Entities/Common/Users/IConnection.cs create mode 100644 src/Discord.Net/Entities/Common/Users/IDMUser.cs create mode 100644 src/Discord.Net/Entities/Common/Users/IGuildUser.cs create mode 100644 src/Discord.Net/Entities/Common/Users/ISelfUser.cs create mode 100644 src/Discord.Net/Entities/Common/Users/IUser.cs rename src/Discord.Net/Entities/{Users/VoiceState.cs => Common/Users/IVoiceState.cs.old} (98%) rename src/Discord.Net/{Enums => Entities/Common/Users}/UserStatus.cs (100%) delete mode 100644 src/Discord.Net/Entities/Guild.cs delete mode 100644 src/Discord.Net/Entities/Helpers/InviteManager.cs delete mode 100644 src/Discord.Net/Entities/Helpers/MentionHelper.cs delete mode 100644 src/Discord.Net/Entities/Helpers/MessageManager.cs delete mode 100644 src/Discord.Net/Entities/Helpers/PermissionManager.cs delete mode 100644 src/Discord.Net/Entities/Helpers/PermissionsHelper.cs delete mode 100644 src/Discord.Net/Entities/IEntity.cs delete mode 100644 src/Discord.Net/Entities/Invites/GuildInvite.cs delete mode 100644 src/Discord.Net/Entities/Invites/IInvite.cs delete mode 100644 src/Discord.Net/Entities/Invites/Invite.cs delete mode 100644 src/Discord.Net/Entities/Invites/InviteChannel.cs delete mode 100644 src/Discord.Net/Entities/Invites/InviteGuild.cs delete mode 100644 src/Discord.Net/Entities/Message.cs delete mode 100644 src/Discord.Net/Entities/Permissions/ChannelPermissions.cs delete mode 100644 src/Discord.Net/Entities/Permissions/GuildPermissions.cs delete mode 100644 src/Discord.Net/Entities/Permissions/OverwritePermissions.cs create mode 100644 src/Discord.Net/Entities/Rest/Channels/DMChannel.cs create mode 100644 src/Discord.Net/Entities/Rest/Channels/GuildChannel.cs create mode 100644 src/Discord.Net/Entities/Rest/Channels/TextChannel.cs create mode 100644 src/Discord.Net/Entities/Rest/Channels/VoiceChannel.cs create mode 100644 src/Discord.Net/Entities/Rest/Guilds/Guild.cs create mode 100644 src/Discord.Net/Entities/Rest/Guilds/GuildEmbed.cs create mode 100644 src/Discord.Net/Entities/Rest/Guilds/GuildIntegration.cs create mode 100644 src/Discord.Net/Entities/Rest/Guilds/IntegrationAccount.cs create mode 100644 src/Discord.Net/Entities/Rest/Guilds/UserGUild.cs create mode 100644 src/Discord.Net/Entities/Rest/Guilds/VoiceRegion.cs create mode 100644 src/Discord.Net/Entities/Rest/Helper/PermissionHelper.cs create mode 100644 src/Discord.Net/Entities/Rest/Invites/GuildInvite.cs create mode 100644 src/Discord.Net/Entities/Rest/Invites/Invite.cs create mode 100644 src/Discord.Net/Entities/Rest/Invites/PublicInvite.cs create mode 100644 src/Discord.Net/Entities/Rest/Message.cs create mode 100644 src/Discord.Net/Entities/Rest/Role.cs create mode 100644 src/Discord.Net/Entities/Rest/Users/Connection.cs create mode 100644 src/Discord.Net/Entities/Rest/Users/DMUser.cs create mode 100644 src/Discord.Net/Entities/Rest/Users/GuildUser.cs create mode 100644 src/Discord.Net/Entities/Rest/Users/PublicUser.cs create mode 100644 src/Discord.Net/Entities/Rest/Users/SelfUser.cs create mode 100644 src/Discord.Net/Entities/Rest/Users/User.cs delete mode 100644 src/Discord.Net/Entities/Role.cs delete mode 100644 src/Discord.Net/Entities/Users/DMUser.cs delete mode 100644 src/Discord.Net/Entities/Users/GlobalUser.cs delete mode 100644 src/Discord.Net/Entities/Users/GuildUser.cs delete mode 100644 src/Discord.Net/Entities/Users/IUser.cs delete mode 100644 src/Discord.Net/Entities/Users/SelfUser.cs delete mode 100644 src/Discord.Net/Entities/VoiceRegion.cs delete mode 100644 src/Discord.Net/Enums/ConnectionState.cs delete mode 100644 src/Discord.Net/Events/ChannelEventArgs.cs delete mode 100644 src/Discord.Net/Events/ChannelUpdatedEventArgs.cs delete mode 100644 src/Discord.Net/Events/CurrentUserEventArgs.cs delete mode 100644 src/Discord.Net/Events/CurrentUserUpdatedEventArgs.cs delete mode 100644 src/Discord.Net/Events/DisconnectedEventArgs.cs delete mode 100644 src/Discord.Net/Events/GuildEventArgs.cs delete mode 100644 src/Discord.Net/Events/GuildUpdatedEventArgs.cs delete mode 100644 src/Discord.Net/Events/MessageEventArgs.cs delete mode 100644 src/Discord.Net/Events/MessageUpdatedEventArgs.cs delete mode 100644 src/Discord.Net/Events/RoleEventArgs.cs delete mode 100644 src/Discord.Net/Events/RoleUpdatedEventArgs.cs create mode 100644 src/Discord.Net/Events/SentRequestEventArgs.cs delete mode 100644 src/Discord.Net/Events/TypingEventArgs.cs delete mode 100644 src/Discord.Net/Events/UserEventArgs.cs delete mode 100644 src/Discord.Net/Events/UserUpdatedEventArgs.cs delete mode 100644 src/Discord.Net/Events/VoiceChannelEventArgs.cs delete mode 100644 src/Discord.Net/Format.cs create mode 100644 src/Discord.Net/Helpers/DateTimeHelper.cs create mode 100644 src/Discord.Net/Helpers/EventExtensions.cs create mode 100644 src/Discord.Net/Helpers/MentionHelper.cs create mode 100644 src/Discord.Net/IDiscordClient.cs delete mode 100644 src/Discord.Net/InternalExtensions.cs rename src/Discord.Net/{Enums => }/LogSeverity.cs (100%) create mode 100644 src/Discord.Net/Logging/ILogger.cs delete mode 100644 src/Discord.Net/MessageQueue.cs rename src/Discord.Net/Net/{JsonConverters => Converters}/ChannelTypeConverter.cs (97%) rename src/Discord.Net/Net/{JsonConverters => Converters}/ImageConverter.cs (96%) rename src/Discord.Net/Net/{JsonConverters => Converters}/NullableUInt64Converter.cs (96%) rename src/Discord.Net/Net/{JsonConverters => Converters}/PermissionTargetConverter.cs (97%) rename src/Discord.Net/Net/{JsonConverters => Converters}/StringEntityConverter.cs (95%) rename src/Discord.Net/Net/{JsonConverters => Converters}/UInt64ArrayConverter.cs (97%) rename src/Discord.Net/Net/{JsonConverters => Converters}/UInt64Converter.cs (95%) rename src/Discord.Net/Net/{JsonConverters => Converters}/UInt64EntityConverter.cs (95%) rename src/Discord.Net/Net/{JsonConverters => Converters}/UserStatusConverter.cs (97%) rename src/Discord.Net/Net/Rest/{DefaultRestEngine.cs => DefaultRestClient.cs} (67%) create mode 100644 src/Discord.Net/Net/Rest/IMessageQueue.cs create mode 100644 src/Discord.Net/Net/Rest/IRestClient.cs delete mode 100644 src/Discord.Net/Net/Rest/IRestEngine.cs delete mode 100644 src/Discord.Net/Net/Rest/IRestRequest.cs create mode 100644 src/Discord.Net/Net/Rest/MultipartFile.cs delete mode 100644 src/Discord.Net/Net/Rest/RestClient.cs delete mode 100644 src/Discord.Net/Net/Rest/RestParameter.cs delete mode 100644 src/Discord.Net/Net/Rest/SentRequestEventArgs.cs delete mode 100644 src/Discord.Net/Net/WebSockets/BinaryMessageEventArgs.cs delete mode 100644 src/Discord.Net/Net/WebSockets/DefaultWebSocketEngine.cs delete mode 100644 src/Discord.Net/Net/WebSockets/GatewaySocket.cs delete mode 100644 src/Discord.Net/Net/WebSockets/IWebSocketEngine.cs delete mode 100644 src/Discord.Net/Net/WebSockets/TextMessageEventArgs.cs delete mode 100644 src/Discord.Net/Net/WebSockets/WebSocket.cs delete mode 100644 src/Discord.Net/Net/WebSockets/WebSocketEventEventArgs.cs delete mode 100644 src/Discord.Net/Net/WebSockets/WebSocketProvider.cs delete mode 100644 src/Discord.Net/TaskHelper.cs create mode 100644 src/Discord.Net/TokenType.cs diff --git a/Discord.Net.sln b/Discord.Net.sln index bfcda2fab..05bfbe216 100644 --- a/Discord.Net.sln +++ b/Discord.Net.sln @@ -1,61 +1,22 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +# Visual Studio 15 +VisualStudioVersion = 15.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", "{2C91BDD7-621D-460F-B768-EAD106D9BA62}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{6317A2E6-8E36-4C3E-949B-3F10EC888AB9}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Tests", "test\Discord.Net.Tests\Discord.Net.Tests.csproj", "{855D6B1D-847B-42DA-BE6A-23683EA89511}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1BE8AF3F-3CFD-433F-A380-D294A4F617C1}" - ProjectSection(SolutionItems) = preProject - global.json = global.json - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "net45", "net45", "{628A40F4-2D06-4BCE-82EF-0EE70DD5C1CA}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Net45", "src\Discord.Net\Discord.Net.Net45.csproj", "{C6A50D24-CBD3-4E76-852C-4DCA60BBD608}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net", "src\Discord.Net.csproj", "{18F6FE23-73F6-4CA6-BBD9-F0139DC3EE90}" EndProject Global 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 - {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 - {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 + {18F6FE23-73F6-4CA6-BBD9-F0139DC3EE90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {18F6FE23-73F6-4CA6-BBD9-F0139DC3EE90}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18F6FE23-73F6-4CA6-BBD9-F0139DC3EE90}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18F6FE23-73F6-4CA6-BBD9-F0139DC3EE90}.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} - {2C91BDD7-621D-460F-B768-EAD106D9BA62} = {EA68EBE2-51C8-4440-9EF7-D633C90A5D35} - {855D6B1D-847B-42DA-BE6A-23683EA89511} = {6317A2E6-8E36-4C3E-949B-3F10EC888AB9} - {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 deleted file mode 100644 index 91bc2845a..000000000 --- a/NuGet.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/global.json b/global.json deleted file mode 100644 index 7f3ac9f7e..000000000 --- a/global.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "projects": [ "src" ], - "sdk": { - "version": "1.0.0-rc2-20221" - } -} \ No newline at end of file diff --git a/src/Discord.Net/CDN.cs b/src/Discord.Net/API/CDN.cs similarity index 94% rename from src/Discord.Net/CDN.cs rename to src/Discord.Net/API/CDN.cs index 11786436b..260feba75 100644 --- a/src/Discord.Net/CDN.cs +++ b/src/Discord.Net/API/CDN.cs @@ -1,8 +1,8 @@ -namespace Discord +namespace Discord.API { internal static class CDN { - public static string GetUserAvatarUrl(ulong userId, string avatarId) + 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; diff --git a/src/Discord.Net/API/Common/Channel.cs b/src/Discord.Net/API/Common/Channel.cs index eb521444c..6dda88944 100644 --- a/src/Discord.Net/API/Common/Channel.cs +++ b/src/Discord.Net/API/Common/Channel.cs @@ -14,11 +14,11 @@ namespace Discord.API //GuildChannel [JsonProperty("guild_id")] - public ulong GuildId { get; set; } + public ulong? GuildId { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("type")] - public string Type { get; set; } + public ChannelType Type { get; set; } [JsonProperty("position")] public int Position { get; set; } [JsonProperty("permission_overwrites")] diff --git a/src/Discord.Net/API/Common/Unconfirmed/Connection.cs b/src/Discord.Net/API/Common/Connection.cs similarity index 81% rename from src/Discord.Net/API/Common/Unconfirmed/Connection.cs rename to src/Discord.Net/API/Common/Connection.cs index a51903273..8022e0314 100644 --- a/src/Discord.Net/API/Common/Unconfirmed/Connection.cs +++ b/src/Discord.Net/API/Common/Connection.cs @@ -1,18 +1,20 @@ using Newtonsoft.Json; +using System.Collections.Generic; 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("type")] + public string Type { get; set; } [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("revoked")] + public bool Revoked { get; set; } + + [JsonProperty("integrations")] + public IEnumerable Integrations { get; set; } } } diff --git a/src/Discord.Net/API/Common/Guild.cs b/src/Discord.Net/API/Common/Guild.cs index cbd50e390..b4dfcdc11 100644 --- a/src/Discord.Net/API/Common/Guild.cs +++ b/src/Discord.Net/API/Common/Guild.cs @@ -26,6 +26,8 @@ namespace Discord.API public ulong? EmbedChannelId { get; set; } [JsonProperty("verification_level")] public int VerificationLevel { get; set; } + [JsonProperty("voice_states")] + public VoiceState[] VoiceStates { get; set; } [JsonProperty("roles")] public Role[] Roles { get; set; } [JsonProperty("emojis")] diff --git a/src/Discord.Net/API/Common/GuildMember.cs b/src/Discord.Net/API/Common/GuildMember.cs index c28d47d34..03da0d5bf 100644 --- a/src/Discord.Net/API/Common/GuildMember.cs +++ b/src/Discord.Net/API/Common/GuildMember.cs @@ -7,6 +7,8 @@ namespace Discord.API { [JsonProperty("user")] public User User { get; set; } + [JsonProperty("nick")] + public string Nick { get; set; } [JsonProperty("roles")] public ulong[] Roles { get; set; } [JsonProperty("joined_at")] diff --git a/src/Discord.Net/API/Common/Unconfirmed/Overwrite.cs b/src/Discord.Net/API/Common/Overwrite.cs similarity index 100% rename from src/Discord.Net/API/Common/Unconfirmed/Overwrite.cs rename to src/Discord.Net/API/Common/Overwrite.cs diff --git a/src/Discord.Net/API/Common/Unconfirmed/ExtendedGuild.cs b/src/Discord.Net/API/Common/Unconfirmed/ExtendedGuild.cs deleted file mode 100644 index 00aaeb7b9..000000000 --- a/src/Discord.Net/API/Common/Unconfirmed/ExtendedGuild.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API -{ - public class ExtendedGuild : Guild - { - [JsonProperty("member_count")] - public int? MemberCount { get; set; } - [JsonProperty("large")] - public bool IsLarge { get; set; } - [JsonProperty("unavailable")] - public bool? Unavailable { get; set; } - - [JsonProperty("channels")] - public Channel[] Channels { get; set; } - [JsonProperty("members")] - public ExtendedMember[] Members { get; set; } - [JsonProperty("presences")] - public MemberPresence[] Presences { get; set; } - [JsonProperty("voice_states")] - public MemberVoiceState[] VoiceStates { get; set; } - } -} diff --git a/src/Discord.Net/API/Common/Unconfirmed/ExtendedMember.cs b/src/Discord.Net/API/Common/Unconfirmed/ExtendedMember.cs deleted file mode 100644 index f09c12e0c..000000000 --- a/src/Discord.Net/API/Common/Unconfirmed/ExtendedMember.cs +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 8148e9b15..000000000 --- a/src/Discord.Net/API/Common/Unconfirmed/MemberPresence.cs +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index acd805548..000000000 --- a/src/Discord.Net/API/Common/Unconfirmed/MemberPresenceGame.cs +++ /dev/null @@ -1,10 +0,0 @@ -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 deleted file mode 100644 index edc41f688..000000000 --- a/src/Discord.Net/API/Common/Unconfirmed/MemberReference.cs +++ /dev/null @@ -1,12 +0,0 @@ -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/Common/Unconfirmed/MessageReference.cs b/src/Discord.Net/API/Common/Unconfirmed/MessageReference.cs deleted file mode 100644 index d2c1dd268..000000000 --- a/src/Discord.Net/API/Common/Unconfirmed/MessageReference.cs +++ /dev/null @@ -1,14 +0,0 @@ -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/RoleReference.cs b/src/Discord.Net/API/Common/Unconfirmed/RoleReference.cs deleted file mode 100644 index bf516faaa..000000000 --- a/src/Discord.Net/API/Common/Unconfirmed/RoleReference.cs +++ /dev/null @@ -1,12 +0,0 @@ -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/UserGuild.cs b/src/Discord.Net/API/Common/UserGuild.cs index 9b0819395..124f64688 100644 --- a/src/Discord.Net/API/Common/UserGuild.cs +++ b/src/Discord.Net/API/Common/UserGuild.cs @@ -12,5 +12,7 @@ namespace Discord.API public string Icon { get; set; } [JsonProperty("owner")] public bool Owner { get; set; } + [JsonProperty("permissions")] + public uint Permissions { get; set; } } } diff --git a/src/Discord.Net/API/Rest/GetVoiceRegions.cs b/src/Discord.Net/API/Common/VoiceRegion.cs similarity index 56% rename from src/Discord.Net/API/Rest/GetVoiceRegions.cs rename to src/Discord.Net/API/Common/VoiceRegion.cs index 5fdbccfd8..83a473142 100644 --- a/src/Discord.Net/API/Rest/GetVoiceRegions.cs +++ b/src/Discord.Net/API/Common/VoiceRegion.cs @@ -1,16 +1,8 @@ -using Discord.Net.Rest; -using Newtonsoft.Json; +using Newtonsoft.Json; -namespace Discord.API.Rest +namespace Discord.API { - public class GetVoiceRegionsRequest : IRestRequest - { - string IRestRequest.Method => "GET"; - string IRestRequest.Endpoint => $"voice/regions"; - object IRestRequest.Payload => null; - } - - public class GetVoiceRegionsResponse + public class VoiceRegion { [JsonProperty("id")] public string Id { get; set; } diff --git a/src/Discord.Net/API/Common/Unconfirmed/MemberVoiceState.cs b/src/Discord.Net/API/Common/VoiceState.cs similarity index 51% rename from src/Discord.Net/API/Common/Unconfirmed/MemberVoiceState.cs rename to src/Discord.Net/API/Common/VoiceState.cs index b79df1790..f584468af 100644 --- a/src/Discord.Net/API/Common/Unconfirmed/MemberVoiceState.cs +++ b/src/Discord.Net/API/Common/VoiceState.cs @@ -2,29 +2,25 @@ namespace Discord.API { - public class MemberVoiceState + public class VoiceState { [JsonProperty("guild_id")] - public ulong GuildId { get; set; } + public ulong? GuildId { get; set; } + [JsonProperty("channel_id")] + public ulong ChannelId { get; set; } [JsonProperty("user_id")] public ulong UserId { get; set; } - - [JsonProperty("channel_id")] - public ulong? ChannelId { get; set; } [JsonProperty("session_id")] public string SessionId { get; set; } - [JsonProperty("token")] - public string Token { get; set; } - - [JsonProperty("self_mute")] - public bool? IsSelfMuted { get; set; } - [JsonProperty("self_deaf")] - public bool? IsSelfDeafened { get; set; } - [JsonProperty("mute")] - public bool? IsMuted { get; set; } [JsonProperty("deaf")] - public bool? IsDeafened { get; set; } + public bool Deaf { get; set; } + [JsonProperty("mute")] + public bool Mute { get; set; } + [JsonProperty("self_deaf")] + public bool SelfDeaf { get; set; } + [JsonProperty("self_mute")] + public bool SelfMute { get; set; } [JsonProperty("suppress")] - public bool? IsSuppressed { get; set; } + public bool Suppress { get; set; } } } diff --git a/src/Discord.Net/API/DiscordRawClient.cs b/src/Discord.Net/API/DiscordRawClient.cs new file mode 100644 index 000000000..575ece0c8 --- /dev/null +++ b/src/Discord.Net/API/DiscordRawClient.cs @@ -0,0 +1,785 @@ +using Discord.API.Rest; +using Discord.Net; +using Discord.Net.Converters; +using Discord.Net.Rest; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Discord.API +{ + public class DiscordRawClient + { + internal event EventHandler SentRequest; + + private readonly IRestClient _restClient; + private readonly CancellationToken _cancelToken; + private readonly JsonSerializer _serializer; + + internal DiscordRawClient(RestClientProvider restClientProvider, CancellationToken cancelToken, TokenType authTokenType, string authToken) + { + _cancelToken = cancelToken; + + switch (authTokenType) + { + case TokenType.Bot: + authToken = $"Bot {authToken}"; + break; + case TokenType.Bearer: + authToken = $"Bearer {authToken}"; + break; + case TokenType.User: + break; + default: + throw new ArgumentException("Unknown oauth token type", nameof(authTokenType)); + } + + _restClient = restClientProvider(DiscordConfig.ClientAPIUrl, cancelToken); + _restClient.SetHeader("authorization", authToken); + _restClient.SetHeader("user-agent", DiscordConfig.UserAgent); + + _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()); + } + + //Core + public async Task Send(string method, string endpoint) + where TResponse : class + { + var stopwatch = Stopwatch.StartNew(); + Stream responseStream; + try + { + responseStream = await _restClient.Send(method, endpoint, (string)null).ConfigureAwait(false); + } + catch (HttpException ex) + { + if (!HandleException(ex)) + throw; + return null; + } + int bytes = (int)responseStream.Length; + stopwatch.Stop(); + var response = Deserialize(responseStream); + + double milliseconds = ToMilliseconds(stopwatch); + SentRequest(this, new SentRequestEventArgs(method, endpoint, bytes, milliseconds)); + + return response; + } + public async Task Send(string method, string endpoint) + { + var stopwatch = Stopwatch.StartNew(); + try + { + await _restClient.Send(method, endpoint, (string)null).ConfigureAwait(false); + } + catch (HttpException ex) + { + if (!HandleException(ex)) + throw; + return; + } + stopwatch.Stop(); + + double milliseconds = ToMilliseconds(stopwatch); + SentRequest(this, new SentRequestEventArgs(method, endpoint, 0, milliseconds)); + } + public async Task Send(string method, string endpoint, object payload) + where TResponse : class + { + string requestStream = Serialize(payload); + var stopwatch = Stopwatch.StartNew(); + Stream responseStream; + try + { + responseStream = await _restClient.Send(method, endpoint, requestStream).ConfigureAwait(false); + } + catch (HttpException ex) + { + if (!HandleException(ex)) + throw; + return null; + } + int bytes = (int)responseStream.Length; + stopwatch.Stop(); + var response = Deserialize(responseStream); + + double milliseconds = ToMilliseconds(stopwatch); + SentRequest(this, new SentRequestEventArgs(method, endpoint, bytes, milliseconds)); + + return response; + } + public async Task Send(string method, string endpoint, object payload) + { + string requestStream = Serialize(payload); + var stopwatch = Stopwatch.StartNew(); + try + { + await _restClient.Send(method, endpoint, requestStream).ConfigureAwait(false); + } + catch (HttpException ex) + { + if (!HandleException(ex)) + throw; + return; + } + stopwatch.Stop(); + + double milliseconds = ToMilliseconds(stopwatch); + SentRequest(this, new SentRequestEventArgs(method, endpoint, 0, milliseconds)); + } + public async Task Send(string method, string endpoint, Stream file, IReadOnlyDictionary multipartArgs) + where TResponse : class + { + var stopwatch = Stopwatch.StartNew(); + var responseStream = await _restClient.Send(method, endpoint).ConfigureAwait(false); + stopwatch.Stop(); + var response = Deserialize(responseStream); + + double milliseconds = ToMilliseconds(stopwatch); + SentRequest(this, new SentRequestEventArgs(method, endpoint, (int)responseStream.Length, milliseconds)); + + return response; + } + public async Task Send(string method, string endpoint, Stream file, IReadOnlyDictionary multipartArgs) + { + var stopwatch = Stopwatch.StartNew(); + await _restClient.Send(method, endpoint).ConfigureAwait(false); + stopwatch.Stop(); + + double milliseconds = ToMilliseconds(stopwatch); + SentRequest(this, new SentRequestEventArgs(method, endpoint, 0, milliseconds)); + } + + //Gateway + public async Task GetGateway() + { + return await Send("GET", "gateway").ConfigureAwait(false); + } + + //Channels + public async Task GetChannel(ulong channelId) + { + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + + try + { + return await Send("GET", $"channels/{channelId}").ConfigureAwait(false); + } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; } + } + public async Task GetChannel(ulong guildId, ulong channelId) + { + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + + try + { + var model = await Send("GET", $"channels/{channelId}").ConfigureAwait(false); + if (model.GuildId != guildId) + return null; + return model; + } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; } + } + public async Task> GetGuildChannels(ulong guildId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + + return await Send>("GET", $"guild/{guildId}/channels").ConfigureAwait(false); + } + public async Task CreateGuildChannel(ulong guildId, CreateGuildChannelParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (args.Bitrate <= 0) throw new ArgumentOutOfRangeException(nameof(args.Bitrate)); + if (args.Name == "") throw new ArgumentOutOfRangeException(nameof(args.Name)); + + return await Send("POST", $"guilds/{guildId}/channels", args).ConfigureAwait(false); + } + public async Task DeleteChannel(ulong channelId) + { + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + + return await Send("DELETE", $"channels/{channelId}").ConfigureAwait(false); + } + public async Task ModifyGuildChannel(ulong channelId, ModifyGuildChannelParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + if (args.Name == "") throw new ArgumentOutOfRangeException(nameof(args.Name)); + if (args.Position < 0) throw new ArgumentOutOfRangeException(nameof(args.Position)); + + return await Send("PATCH", $"channels/{channelId}", args).ConfigureAwait(false); + } + public async Task ModifyGuildChannel(ulong channelId, ModifyTextChannelParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + if (args.Name == "") throw new ArgumentOutOfRangeException(nameof(args.Name)); + if (args.Position < 0) throw new ArgumentOutOfRangeException(nameof(args.Position)); + + return await Send("PATCH", $"channels/{channelId}", args).ConfigureAwait(false); + } + public async Task ModifyGuildChannel(ulong channelId, ModifyVoiceChannelParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + if (args.Bitrate <= 0) throw new ArgumentOutOfRangeException(nameof(args.Bitrate)); + if (args.Name == "") throw new ArgumentOutOfRangeException(nameof(args.Name)); + if (args.Position < 0) throw new ArgumentOutOfRangeException(nameof(args.Position)); + + return await Send("PATCH", $"channels/{channelId}", args).ConfigureAwait(false); + } + public async Task ModifyGuildChannels(ulong guildId, IEnumerable args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + + var channels = args.ToArray(); + switch (channels.Length) + { + case 0: + throw new ArgumentOutOfRangeException(nameof(args)); + case 1: + await ModifyGuildChannel(channels[0].Id, new ModifyGuildChannelParams { Position = channels[0].Position }).ConfigureAwait(false); + break; + default: + await Send("PATCH", $"guilds/{guildId}/channels", channels).ConfigureAwait(false); + break; + } + } + + //Channel Permissions + public async Task ModifyChannelPermissions(ulong channelId, ulong targetId, ModifyChannelPermissionsParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + await Send("PUT", $"channels/{channelId}/permissions/{targetId}", args).ConfigureAwait(false); + } + public async Task DeleteChannelPermission(ulong channelId, ulong targetId) + { + await Send("DELETE", $"channels/{channelId}/permissions/{targetId}").ConfigureAwait(false); + } + + //Guilds + public async Task GetGuild(ulong guildId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + + try + { + return await Send("GET", $"guilds/{guildId}").ConfigureAwait(false); + } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; } + } + public async Task CreateGuild(CreateGuildParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (string.IsNullOrEmpty(args.Name)) throw new ArgumentNullException(nameof(args.Name)); + if (string.IsNullOrEmpty(args.Region)) throw new ArgumentNullException(nameof(args.Region)); + + return await Send("POST", "guilds", args).ConfigureAwait(false); + } + public async Task DeleteGuild(ulong guildId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + + return await Send("DELETE", $"guilds/{guildId}").ConfigureAwait(false); + } + public async Task LeaveGuild(ulong guildId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + + return await Send("DELETE", $"users/@me/guilds/{guildId}").ConfigureAwait(false); + } + public async Task ModifyGuild(ulong guildId, ModifyGuildParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (args.AFKChannelId == 0) throw new ArgumentOutOfRangeException(nameof(args.AFKChannelId)); + if (args.AFKTimeout < 0) throw new ArgumentOutOfRangeException(nameof(args.AFKTimeout)); + if (args.Name == "") throw new ArgumentOutOfRangeException(nameof(args.Name)); + //if (args.OwnerId == 0) throw new ArgumentOutOfRangeException(nameof(args.OwnerId)); + //if (args.Region == "") throw new ArgumentOutOfRangeException(nameof(args.Region)); + if (args.VerificationLevel < 0) throw new ArgumentOutOfRangeException(nameof(args.VerificationLevel)); + + return await Send("PATCH", $"guilds/{guildId}", args).ConfigureAwait(false); + } + public async Task BeginGuildPrune(ulong guildId, GuildPruneParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (args.Days < 0) throw new ArgumentOutOfRangeException(nameof(args.Days)); + + return await Send("POST", $"guilds/{guildId}/prune", args).ConfigureAwait(false); + } + public async Task GetGuildPruneCount(ulong guildId, GuildPruneParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (args.Days < 0) throw new ArgumentOutOfRangeException(nameof(args.Days)); + + return await Send("GET", $"guilds/{guildId}/prune", args).ConfigureAwait(false); + } + + //Guild Bans + public async Task> GetGuildBans(ulong guildId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + + return await Send>("GET", $"guilds/{guildId}/bans").ConfigureAwait(false); + } + public async Task CreateGuildBan(ulong guildId, ulong userId, CreateGuildBanParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (userId == 0) throw new ArgumentOutOfRangeException(nameof(userId)); + if (args.PruneDays < 0) throw new ArgumentOutOfRangeException(nameof(args.PruneDays)); + + await Send("PUT", $"guilds/{guildId}/bans/{userId}", args).ConfigureAwait(false); + } + public async Task RemoveGuildBan(ulong guildId, ulong userId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (userId == 0) throw new ArgumentOutOfRangeException(nameof(userId)); + + await Send("DELETE", $"guilds/{guildId}/bans/{userId}").ConfigureAwait(false); + } + + //Guild Embeds + public async Task GetGuildEmbed(ulong guildId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + + try + { + return await Send("GET", $"guilds/{guildId}/embed").ConfigureAwait(false); + } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; } + } + public async Task ModifyGuildEmbed(ulong guildId, ModifyGuildEmbedParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + + return await Send("PATCH", $"guilds/{guildId}/embed", args).ConfigureAwait(false); + } + + //Guild Integrations + public async Task> GetGuildIntegrations(ulong guildId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + + return await Send>("GET", $"guilds/{guildId}/integrations").ConfigureAwait(false); + } + public async Task CreateGuildIntegration(ulong guildId, CreateGuildIntegrationParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (args.Id == 0) throw new ArgumentOutOfRangeException(nameof(args.Id)); + + return await Send("POST", $"guilds/{guildId}/integrations").ConfigureAwait(false); + } + public async Task DeleteGuildIntegration(ulong guildId, ulong integrationId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (integrationId == 0) throw new ArgumentOutOfRangeException(nameof(integrationId)); + + return await Send("DELETE", $"guilds/{guildId}/integrations/{integrationId}").ConfigureAwait(false); + } + public async Task ModifyGuildIntegration(ulong guildId, ulong integrationId, ModifyGuildIntegrationParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (integrationId == 0) throw new ArgumentOutOfRangeException(nameof(integrationId)); + if (args.ExpireBehavior < 0) throw new ArgumentOutOfRangeException(nameof(args.ExpireBehavior)); + if (args.ExpireGracePeriod < 0) throw new ArgumentOutOfRangeException(nameof(args.ExpireGracePeriod)); + + return await Send("PATCH", $"guilds/{guildId}/integrations/{integrationId}", args).ConfigureAwait(false); + } + public async Task SyncGuildIntegration(ulong guildId, ulong integrationId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (integrationId == 0) throw new ArgumentOutOfRangeException(nameof(integrationId)); + + return await Send("POST", $"guilds/{guildId}/integrations/{integrationId}/sync").ConfigureAwait(false); + } + + //Guild Invites + public async Task GetInvite(string inviteIdOrXkcd) + { + if (string.IsNullOrEmpty(inviteIdOrXkcd)) throw new ArgumentOutOfRangeException(nameof(inviteIdOrXkcd)); + + try + { + return await Send("GET", $"invites/{inviteIdOrXkcd}").ConfigureAwait(false); + } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; } + } + public async Task> GetGuildInvites(ulong guildId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + + return await Send>("GET", $"guilds/{guildId}/invites").ConfigureAwait(false); + } + public async Task GetChannelInvites(ulong channelId) + { + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + + return await Send("GET", $"channels/{channelId}/invites").ConfigureAwait(false); + } + public async Task CreateChannelInvite(ulong channelId, CreateChannelInviteParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + if (args.MaxAge < 0) throw new ArgumentOutOfRangeException(nameof(args.MaxAge)); + if (args.MaxUses < 0) throw new ArgumentOutOfRangeException(nameof(args.MaxUses)); + + return await Send("POST", $"channels/{channelId}/invites", args).ConfigureAwait(false); + } + public async Task DeleteInvite(string inviteCode) + { + if (string.IsNullOrEmpty(inviteCode)) throw new ArgumentOutOfRangeException(nameof(inviteCode)); + + return await Send("DELETE", $"invites/{inviteCode}").ConfigureAwait(false); + } + public async Task AcceptInvite(string inviteCode) + { + if (string.IsNullOrEmpty(inviteCode)) throw new ArgumentOutOfRangeException(nameof(inviteCode)); + + await Send("POST", $"invites/{inviteCode}").ConfigureAwait(false); + } + + //Guild Members + public async Task GetGuildMember(ulong guildId, ulong userId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (userId == 0) throw new ArgumentOutOfRangeException(nameof(userId)); + + try + { + return await Send("GET", $"guilds/{guildId}/members/{userId}").ConfigureAwait(false); + } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; } + } + public async Task> GetGuildMembers(ulong guildId, GetGuildMembersParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (args.Limit <= 0) throw new ArgumentOutOfRangeException(nameof(args.Limit)); + if (args.Offset < 0) throw new ArgumentOutOfRangeException(nameof(args.Offset)); + + int limit = args.Limit ?? int.MaxValue; + int offset = args.Offset; + + List result; + if (args.Limit != null) + result = new List((limit + DiscordConfig.MaxUsersPerBatch - 1) / DiscordConfig.MaxUsersPerBatch); + else + result = new List(); + + while (true) + { + int runLimit = (limit >= DiscordConfig.MaxUsersPerBatch) ? DiscordConfig.MaxUsersPerBatch : limit; + string endpoint = $"guild/{guildId}/members?limit={limit}&offset={offset}"; + var models = await Send("GET", endpoint).ConfigureAwait(false); + + //Was this an empty batch? + if (models.Length == 0) break; + + result.Add(models); + + limit -= DiscordConfig.MaxUsersPerBatch; + + //Was this an incomplete (the last) batch? + if (models.Length != DiscordConfig.MaxUsersPerBatch) break; + } + + if (result.Count > 1) + return result.SelectMany(x => x); + else + return result[0]; + } + public async Task RemoveGuildMember(ulong guildId, ulong userId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (userId == 0) throw new ArgumentOutOfRangeException(nameof(userId)); + + await Send("DELETE", $"guilds/{guildId}/members/{userId}").ConfigureAwait(false); + } + public async Task ModifyGuildMember(ulong guildId, ulong userId, ModifyGuildMemberParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (userId == 0) throw new ArgumentOutOfRangeException(nameof(userId)); + + return await Send("PATCH", $"guilds/{guildId}/members/{userId}", args).ConfigureAwait(false); + } + + //Guild Roles + public async Task> GetGuildRoles(ulong guildId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + + return await Send>("GET", $"guild/{guildId}/roles").ConfigureAwait(false); + } + public async Task CreateGuildRole(ulong guildId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + + return await Send("POST", $"guilds/{guildId}/roles").ConfigureAwait(false); + } + public async Task DeleteGuildRole(ulong guildId, ulong roleId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (roleId == 0) throw new ArgumentOutOfRangeException(nameof(roleId)); + + await Send("DELETE", $"guilds/{guildId}/roles/{roleId}").ConfigureAwait(false); + } + public async Task ModifyGuildRole(ulong guildId, ulong roleId, ModifyGuildRoleParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + if (roleId == 0) throw new ArgumentOutOfRangeException(nameof(roleId)); + if (args.Color < 0) throw new ArgumentOutOfRangeException(nameof(args.Color)); + if (args.Name == "") throw new ArgumentOutOfRangeException(nameof(args.Name)); + if (args.Position < 0) throw new ArgumentOutOfRangeException(nameof(args.Position)); + + return await Send("PATCH", $"guilds/{guildId}/roles/{roleId}", args).ConfigureAwait(false); + } + public async Task> ModifyGuildRoles(ulong guildId, IEnumerable args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + + var roles = args.ToArray(); + switch (roles.Length) + { + case 0: + throw new ArgumentOutOfRangeException(nameof(args)); + case 1: + return ImmutableArray.Create(await ModifyGuildRole(guildId, roles[0].Id, roles[0]).ConfigureAwait(false)); + default: + return await Send>("PATCH", $"guilds/{guildId}/roles", args).ConfigureAwait(false); + } + } + + //Messages + public async Task> GetChannelMessages(ulong channelId, GetChannelMessagesParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + if (args.Limit <= 0) throw new ArgumentOutOfRangeException(nameof(args.Limit)); + + int limit = args.Limit; + ulong? relativeId = args.RelativeMessageId; + string relativeDir = args.RelativeDirection == Direction.After ? "after" : "before"; + + int runs = limit / DiscordConfig.MaxMessagesPerBatch; + int lastRunCount = limit - runs * DiscordConfig.MaxMessagesPerBatch; + var result = new API.Message[runs][]; + + int i = 0; + for (; i < runs; i++) + { + string endpoint; + if (relativeId != null) + endpoint = $"channels/{channelId}/messages?limit={limit}&{relativeDir}={relativeId}"; + else + endpoint = $"channels/{channelId}/messages?limit={limit}"; + var models = await Send("GET", endpoint).ConfigureAwait(false); + + //Was this an empty batch? + if (models.Length == 0) break; + + result[i] = models; + + limit = (i == runs - 1) ? lastRunCount : DiscordConfig.MaxMessagesPerBatch; + relativeId = args.RelativeDirection == Direction.Before ? models[0].Id : models[models.Length - 1].Id; + + //Was this an incomplete (the last) batch? + if (models.Length != DiscordConfig.MaxMessagesPerBatch) { i++; break; } + } + + if (runs > 1) + return result.Take(runs).SelectMany(x => x); + else + return result[0]; + } + public async Task CreateMessage(ulong channelId, CreateMessageParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + + return await Send("POST", $"channels/{channelId}/messages", args).ConfigureAwait(false); + } + public async Task UploadFile(ulong channelId, Stream file, UploadFileParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + + return await Send("POST", $"channels/{channelId}/messages", file, args.ToDictionary()).ConfigureAwait(false); + } + public async Task DeleteMessage(ulong channelId, ulong messageId) + { + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + if (messageId == 0) throw new ArgumentOutOfRangeException(nameof(messageId)); + + await Send("DELETE", $"channels/{channelId}/messages/{messageId}").ConfigureAwait(false); + } + public async Task DeleteMessages(ulong channelId, DeleteMessagesParam args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (args.MessageIds == null) throw new ArgumentNullException(nameof(args.MessageIds)); + + var messageIds = args.MessageIds.ToArray(); + switch (messageIds.Length) + { + case 0: + throw new ArgumentOutOfRangeException(nameof(args.MessageIds)); + case 1: + await DeleteMessage(channelId, messageIds[0]).ConfigureAwait(false); + break; + default: + await Send("POST", $"channels/{channelId}/messages/bulk_delete", args).ConfigureAwait(false); + break; + } + } + public async Task ModifyMessage(ulong channelId, ulong messageId, ModifyMessageParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + if (messageId == 0) throw new ArgumentOutOfRangeException(nameof(messageId)); + + return await Send("PATCH", $"channels/{channelId}/messages/{messageId}", args).ConfigureAwait(false); + } + public async Task AckMessage(ulong channelId, ulong messageId) + { + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + if (messageId == 0) throw new ArgumentOutOfRangeException(nameof(messageId)); + + await Send("POST", $"channels/{channelId}/messages/{messageId}/ack").ConfigureAwait(false); + } + public async Task TriggerTypingIndicator(ulong channelId) + { + if (channelId == 0) throw new ArgumentOutOfRangeException(nameof(channelId)); + + await Send("POST", $"channels/{channelId}/typing").ConfigureAwait(false); + } + + //Users + public async Task GetUser(ulong userId) + { + if (userId == 0) throw new ArgumentOutOfRangeException(nameof(userId)); + + try + { + return await Send("GET", $"users/{userId}").ConfigureAwait(false); + } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; } + } + public async Task GetUser(string username, ushort discriminator) + { + if (string.IsNullOrEmpty(username)) throw new ArgumentOutOfRangeException(nameof(username)); + + try + { + var models = await QueryUsers($"{username}#{discriminator}", 1).ConfigureAwait(false); + return models.FirstOrDefault(); + } + catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { return null; } + } + public async Task> QueryUsers(string query, int limit) + { + if (string.IsNullOrEmpty(query)) throw new ArgumentOutOfRangeException(nameof(query)); + if (limit <= 0) throw new ArgumentOutOfRangeException(nameof(limit)); + + return await Send>("GET", $"users?q={Uri.EscapeDataString(query)}&limit={limit}").ConfigureAwait(false); + } + + //Current User/DMs + public async Task GetCurrentUser() + { + return await Send("GET", "users/@me").ConfigureAwait(false); + } + public async Task> GetCurrentUserConnections() + { + return await Send>("GET", "users/@me/connections").ConfigureAwait(false); + } + public async Task> GetCurrentUserDMs() + { + return await Send>("GET", "users/@me/channels").ConfigureAwait(false); + } + public async Task> GetCurrentUserGuilds() + { + return await Send>("GET", "users/@me/guilds").ConfigureAwait(false); + } + public async Task ModifyCurrentUser(ModifyCurrentUserParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (args.Email == "") throw new ArgumentOutOfRangeException(nameof(args.Email)); + if (args.Username == "") throw new ArgumentOutOfRangeException(nameof(args.Username)); + + return await Send("PATCH", "users/@me", args).ConfigureAwait(false); + } + public async Task CreateDMChannel(CreateDMChannelParams args) + { + if (args == null) throw new ArgumentNullException(nameof(args)); + if (args.RecipientId == 0) throw new ArgumentOutOfRangeException(nameof(args.RecipientId)); + + return await Send("POST", $"users/@me/channels", args).ConfigureAwait(false); + } + + //Voice Regions + public async Task> GetVoiceRegions() + { + return await Send>("GET", "voice/regions").ConfigureAwait(false); + } + public async Task> GetGuildVoiceRegions(ulong guildId) + { + if (guildId == 0) throw new ArgumentOutOfRangeException(nameof(guildId)); + + return await Send>("GET", $"guilds/{guildId}/regions").ConfigureAwait(false); + } + + //Helpers + private static double ToMilliseconds(Stopwatch stopwatch) => Math.Round((double)stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0, 2); + private string Serialize(object value) + { + var sb = new StringBuilder(256); + using (TextWriter text = new StringWriter(sb, CultureInfo.InvariantCulture)) + using (JsonWriter writer = new JsonTextWriter(text)) + _serializer.Serialize(writer, value); + return sb.ToString(); + } + private T Deserialize(Stream jsonStream) + { + using (TextReader text = new StreamReader(jsonStream)) + using (JsonReader reader = new JsonTextReader(text)) + return _serializer.Deserialize(reader); + } + + private bool HandleException(Exception ex) + { + //TODO: Implement... maybe via SentRequest? Need to bubble this up to DiscordClient or a MessageQueue + return false; + } + } +} diff --git a/src/Discord.Net/API/GatewaySocket/OpCode.cs b/src/Discord.Net/API/GatewaySocket/OpCode.cs deleted file mode 100644 index cf8e142ef..000000000 --- a/src/Discord.Net/API/GatewaySocket/OpCode.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public enum OpCode : byte - { - /// C←S - Used to send most events. - Dispatch = 0, - /// C↔S - Used to keep the connection alive and measure latency. - Heartbeat = 1, - /// C→S - Used to associate a connection with a token and specify configuration. - Identify = 2, - /// C→S - Used to update client's status and current game id. - StatusUpdate = 3, - /// C→S - Used to join a particular voice channel. - VoiceStateUpdate = 4, - /// 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. - 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 deleted file mode 100644 index 5dac73ec5..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Heartbeat.cs +++ /dev/null @@ -1,12 +0,0 @@ -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/GatewaySocket/Unconfirmed/Commands/Identify.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Identify.cs deleted file mode 100644 index 235f615ef..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Identify.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Newtonsoft.Json; -using System.Collections.Generic; - -namespace Discord.API.GatewaySocket -{ - [JsonObject(MemberSerialization.OptIn)] - public class IdentifyCommand : IWebSocketMessage - { - int IWebSocketMessage.OpCode => (int)OpCode.Identify; - object IWebSocketMessage.Payload => this; - - [JsonProperty("v")] - public int Version { get; set; } - [JsonProperty("token")] - public string Token { get; set; } - [JsonProperty("properties")] - public IReadOnlyDictionary Properties { get; set; } - [JsonProperty("large_threshold", NullValueHandling = NullValueHandling.Ignore)] - public int LargeThreshold { get; set; } - [JsonProperty("compress")] - public bool UseCompression { get; set; } - } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/RequestMembers.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/RequestMembers.cs deleted file mode 100644 index c4614284d..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/RequestMembers.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.GatewaySocket -{ - [JsonObject(MemberSerialization.OptIn)] - public class RequestMembersCommand : IWebSocketMessage - { - int IWebSocketMessage.OpCode => (int)OpCode.RequestGuildMembers; - object IWebSocketMessage.Payload => this; - - [JsonProperty("guild_id")] - public ulong[] GuildId { get; set; } - [JsonProperty("query")] - public string Query { get; set; } - [JsonProperty("limit")] - public int Limit { get; set; } - } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Resume.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Resume.cs deleted file mode 100644 index 1525c6b6a..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/Resume.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.GatewaySocket -{ - [JsonObject(MemberSerialization.OptIn)] - public class ResumeCommand : IWebSocketMessage - { - int IWebSocketMessage.OpCode => (int)OpCode.Resume; - object IWebSocketMessage.Payload => this; - - [JsonProperty("session_id")] - public string SessionId { get; set; } - [JsonProperty("seq")] - public uint Sequence { get; set; } - } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/UpdateStatus.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/UpdateStatus.cs deleted file mode 100644 index 8aa22ede5..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/UpdateStatus.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.GatewaySocket -{ - [JsonObject(MemberSerialization.OptIn)] - public class UpdateStatusCommand : IWebSocketMessage - { - int IWebSocketMessage.OpCode => (int)OpCode.StatusUpdate; - object IWebSocketMessage.Payload => this; - - public class GameInfo - { - [JsonProperty("name")] - public string Name { get; set; } - } - - [JsonProperty("idle_since")] - public long? IdleSince { get; set; } - [JsonProperty("game")] - public GameInfo Game { get; set; } - } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/UpdateVoice.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/UpdateVoice.cs deleted file mode 100644 index d7befa41e..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Commands/UpdateVoice.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.GatewaySocket -{ - [JsonObject(MemberSerialization.OptIn)] - public class UpdateVoiceCommand : IWebSocketMessage - { - int IWebSocketMessage.OpCode => (int)OpCode.VoiceStateUpdate; - object IWebSocketMessage.Payload => this; - - [JsonProperty("guild_id")] - public ulong? GuildId { get; set; } - [JsonProperty("channel_id")] - public ulong? ChannelId { get; set; } - [JsonProperty("self_mute")] - public bool IsSelfMuted { get; set; } - [JsonProperty("self_deaf")] - public bool IsSelfDeafened { get; set; } - } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelCreate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelCreate.cs deleted file mode 100644 index 1e2769036..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelCreate.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class ChannelCreateEvent : Channel { } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelDelete.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelDelete.cs deleted file mode 100644 index 91c57d640..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelDelete.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class ChannelDeleteEvent : Channel { } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelUpdate.cs deleted file mode 100644 index 227124291..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/ChannelUpdate.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class ChannelUpdateEvent : Channel { } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildBanAdd.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildBanAdd.cs deleted file mode 100644 index c1149ee15..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildBanAdd.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class GuildBanAddEvent : MemberReference { } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildBanRemove.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildBanRemove.cs deleted file mode 100644 index 5474146a7..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildBanRemove.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class GuildBanRemoveEvent : MemberReference { } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildCreate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildCreate.cs deleted file mode 100644 index f07adaed3..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildCreate.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class GuildCreateEvent : ExtendedGuild { } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildDelete.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildDelete.cs deleted file mode 100644 index 3408183ad..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildDelete.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class GuildDeleteEvent : ExtendedGuild { } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberAdd.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberAdd.cs deleted file mode 100644 index 098a2ea3b..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberAdd.cs +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 686af9511..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberRemove.cs +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 339489f76..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMemberUpdate.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class GuildMemberUpdateEvent : GuildMember { } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMembersChunk.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMembersChunk.cs deleted file mode 100644 index 72936dd16..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildMembersChunk.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.GatewaySocket -{ - public class GuildMembersChunkEvent - { - [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 deleted file mode 100644 index 2740546dc..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleCreate.cs +++ /dev/null @@ -1,12 +0,0 @@ -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/GatewaySocket/Unconfirmed/Events/GuildRoleDelete.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleDelete.cs deleted file mode 100644 index 4986f6193..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleDelete.cs +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 56c232d06..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildRoleUpdate.cs +++ /dev/null @@ -1,12 +0,0 @@ -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/GatewaySocket/Unconfirmed/Events/GuildUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildUpdate.cs deleted file mode 100644 index b292c54e6..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/GuildUpdate.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class GuildUpdateEvent : Guild { } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageAck.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageAck.cs deleted file mode 100644 index c8379d369..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageAck.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class MessageAckEvent : MessageReference { } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageCreate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageCreate.cs deleted file mode 100644 index 6b0e1e024..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageCreate.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class MessageCreateEvent : Message { } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageDelete.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageDelete.cs deleted file mode 100644 index d932960ba..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageDelete.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class MessageDeleteEvent : MessageReference { } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageUpdate.cs deleted file mode 100644 index 39ef7e1ba..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/MessageUpdate.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class MessageUpdateEvent : Message { } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/PresenceUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/PresenceUpdate.cs deleted file mode 100644 index 59d915354..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/PresenceUpdate.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class PresenceUpdateEvent : MemberPresence { } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Ready.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Ready.cs deleted file mode 100644 index 51e0f3c8c..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Ready.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.GatewaySocket -{ - public class ReadyEvent - { - public class ReadState - { - [JsonProperty("id")] - public string ChannelId { get; set; } - [JsonProperty("mention_count")] - public int MentionCount { get; set; } - [JsonProperty("last_message_id")] - public string LastMessageId { get; set; } - } - - [JsonProperty("v")] - public int Version { get; set; } - [JsonProperty("user")] - public User User { get; set; } - [JsonProperty("session_id")] - public string SessionId { get; set; } - [JsonProperty("read_state")] - public ReadState[] ReadStates { get; set; } - [JsonProperty("guilds")] - public ExtendedGuild[] Guilds { get; set; } - [JsonProperty("private_channels")] - public Channel[] PrivateChannels { get; set; } - [JsonProperty("heartbeat_interval")] - public int HeartbeatInterval { get; set; } - - //Ignored - [JsonProperty("user_settings")] - public object UserSettings { get; set; } - [JsonProperty("user_guild_settings")] - public object UserGuildSettings { get; set; } - [JsonProperty("tutorial")] - public object Tutorial { get; set; } - } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Resumed.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Resumed.cs deleted file mode 100644 index 3f98b1f35..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Resumed.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.GatewaySocket -{ - public class ResumedEvent - { - [JsonProperty("heartbeat_interval")] - public int HeartbeatInterval { get; set; } - } -} diff --git a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/TypingStart.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/TypingStart.cs deleted file mode 100644 index 063011bbb..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/TypingStart.cs +++ /dev/null @@ -1,14 +0,0 @@ -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/GatewaySocket/Unconfirmed/Events/UserUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/UserUpdate.cs deleted file mode 100644 index e49f8b292..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/UserUpdate.cs +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 75936bb93..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/VoiceServerUpdate.cs +++ /dev/null @@ -1,14 +0,0 @@ -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/GatewaySocket/Unconfirmed/Events/VoiceStateUpdate.cs b/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/VoiceStateUpdate.cs deleted file mode 100644 index c0b99c710..000000000 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/VoiceStateUpdate.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Discord.API.GatewaySocket -{ - public class VoiceStateUpdateEvent : MemberVoiceState { } -} diff --git a/src/Discord.Net/API/IWebSocketMessage.cs b/src/Discord.Net/API/IWebSocketMessage.cs deleted file mode 100644 index 06c51bf77..000000000 --- a/src/Discord.Net/API/IWebSocketMessage.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API -{ - public interface IWebSocketMessage - { - int OpCode { get; } - object Payload { get; } - } - public class WebSocketMessage - { - [JsonProperty("op")] - public int? Operation { get; set; } - [JsonProperty("t", NullValueHandling = NullValueHandling.Ignore)] - public string Type { get; set; } - [JsonProperty("s", NullValueHandling = NullValueHandling.Ignore)] - public uint? Sequence { get; set; } - [JsonProperty("d")] - public object Payload { get; set; } - - public WebSocketMessage() { } - public WebSocketMessage(IWebSocketMessage msg) - { - Operation = msg.OpCode; - Payload = msg.Payload; - } - } -} diff --git a/src/Discord.Net/API/Rest/AcceptInvite.cs b/src/Discord.Net/API/Rest/AcceptInvite.cs deleted file mode 100644 index 72350253f..000000000 --- a/src/Discord.Net/API/Rest/AcceptInvite.cs +++ /dev/null @@ -1,18 +0,0 @@ -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/Rest/AckMessage.cs b/src/Discord.Net/API/Rest/AckMessage.cs deleted file mode 100644 index 387215624..000000000 --- a/src/Discord.Net/API/Rest/AckMessage.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Discord.Net.Rest; - -namespace Discord.API.Rest -{ - public class AckMessageRequest : IRestRequest - { - string IRestRequest.Method => "POST"; - string IRestRequest.Endpoint => $"channels/{ChannelId}/messages/{MessageId}/ack"; - object IRestRequest.Payload => null; - - public ulong ChannelId { get; } - public ulong MessageId { get; } - - public AckMessageRequest(ulong channelId, ulong messageId) - { - ChannelId = channelId; - MessageId = messageId; - } - } -} diff --git a/src/Discord.Net/API/Rest/BeginGuildPrune.cs b/src/Discord.Net/API/Rest/BeginGuildPrune.cs deleted file mode 100644 index 0a35bdc80..000000000 --- a/src/Discord.Net/API/Rest/BeginGuildPrune.cs +++ /dev/null @@ -1,23 +0,0 @@ -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/Rest/CreateChannelInvite.cs b/src/Discord.Net/API/Rest/CreateChannelInvite.cs deleted file mode 100644 index f60232f48..000000000 --- a/src/Discord.Net/API/Rest/CreateChannelInvite.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Discord.Net.Rest; -using Newtonsoft.Json; - -namespace Discord.API.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class CreateChannelInviteRequest : IRestRequest - { - string IRestRequest.Method => "POST"; - string IRestRequest.Endpoint => $"channels/{ChannelId}/invites"; - object IRestRequest.Payload => this; - - public ulong ChannelId { get; } - - [JsonProperty("max_age")] - 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; - - public CreateChannelInviteRequest(ulong channelId) - { - ChannelId = channelId; - } - } -} diff --git a/src/Discord.Net/API/Rest/CreateChannelInviteParams.cs b/src/Discord.Net/API/Rest/CreateChannelInviteParams.cs new file mode 100644 index 000000000..570259867 --- /dev/null +++ b/src/Discord.Net/API/Rest/CreateChannelInviteParams.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class CreateChannelInviteParams + { + [JsonProperty("max_age")] + public int MaxAge { get; set; } = 86400; //24 Hours + [JsonProperty("max_uses")] + public int MaxUses { get; set; } = 0; + [JsonProperty("temporary")] + public bool Temporary { get; set; } = false; + [JsonProperty("xkcdpass")] + public bool XkcdPass { get; set; } = false; + } +} diff --git a/src/Discord.Net/API/Rest/CreateDMChannel.cs b/src/Discord.Net/API/Rest/CreateDMChannel.cs deleted file mode 100644 index 473ecc8e2..000000000 --- a/src/Discord.Net/API/Rest/CreateDMChannel.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Discord.Net.Rest; -using Newtonsoft.Json; - -namespace Discord.API.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class CreateDMChannelRequest : IRestRequest - { - string IRestRequest.Method => "POST"; - string IRestRequest.Endpoint => $"users/@me/channels"; - object IRestRequest.Payload => this; - - [JsonProperty("recipient_id")] - public ulong RecipientId { get; set; } - } -} diff --git a/src/Discord.Net/API/Rest/CreateDMChannelParams.cs b/src/Discord.Net/API/Rest/CreateDMChannelParams.cs new file mode 100644 index 000000000..9ce033783 --- /dev/null +++ b/src/Discord.Net/API/Rest/CreateDMChannelParams.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class CreateDMChannelParams + { + [JsonProperty("recipient_id")] + public ulong RecipientId { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/CreateGuildBan.cs b/src/Discord.Net/API/Rest/CreateGuildBan.cs deleted file mode 100644 index c76122c5f..000000000 --- a/src/Discord.Net/API/Rest/CreateGuildBan.cs +++ /dev/null @@ -1,24 +0,0 @@ -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/Rest/CreateGuildBanParams.cs b/src/Discord.Net/API/Rest/CreateGuildBanParams.cs new file mode 100644 index 000000000..b8bf5b5cc --- /dev/null +++ b/src/Discord.Net/API/Rest/CreateGuildBanParams.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class CreateGuildBanParams + { + [JsonProperty("delete-message-days")] + public int PruneDays { get; set; } = 0; + } +} diff --git a/src/Discord.Net/API/Rest/CreateGuildChannel.cs b/src/Discord.Net/API/Rest/CreateGuildChannel.cs deleted file mode 100644 index 73791825f..000000000 --- a/src/Discord.Net/API/Rest/CreateGuildChannel.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Discord.Net.Rest; -using Newtonsoft.Json; - -namespace Discord.API.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class CreateGuildChannelRequest : IRestRequest - { - string IRestRequest.Method => "POST"; - string IRestRequest.Endpoint => $"guilds/{GuildId}/channels"; - object IRestRequest.Payload => this; - - 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 CreateGuildChannelRequest(ulong guildId) - { - GuildId = guildId; - } - } -} diff --git a/src/Discord.Net/API/Rest/CreateGuildChannelParams.cs b/src/Discord.Net/API/Rest/CreateGuildChannelParams.cs new file mode 100644 index 000000000..2badcf27c --- /dev/null +++ b/src/Discord.Net/API/Rest/CreateGuildChannelParams.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class CreateGuildChannelParams + { + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("type")] + public ChannelType Type { get; set; } + [JsonProperty("bitrate")] + public int Bitrate { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/CreateGuildIntegration.cs b/src/Discord.Net/API/Rest/CreateGuildIntegration.cs deleted file mode 100644 index 7cf48397d..000000000 --- a/src/Discord.Net/API/Rest/CreateGuildIntegration.cs +++ /dev/null @@ -1,25 +0,0 @@ -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/Rest/CreateGuildIntegrationParams.cs b/src/Discord.Net/API/Rest/CreateGuildIntegrationParams.cs new file mode 100644 index 000000000..8107548ac --- /dev/null +++ b/src/Discord.Net/API/Rest/CreateGuildIntegrationParams.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class CreateGuildIntegrationParams + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("type")] + public string Type { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/CreateGuild.cs b/src/Discord.Net/API/Rest/CreateGuildParams.cs similarity index 52% rename from src/Discord.Net/API/Rest/CreateGuild.cs rename to src/Discord.Net/API/Rest/CreateGuildParams.cs index c2c9532e0..d8563adbd 100644 --- a/src/Discord.Net/API/Rest/CreateGuild.cs +++ b/src/Discord.Net/API/Rest/CreateGuildParams.cs @@ -1,17 +1,11 @@ -using Discord.Net.JsonConverters; -using Discord.Net.Rest; +using Discord.Net.Converters; using Newtonsoft.Json; using System.IO; namespace Discord.API.Rest { - [JsonObject(MemberSerialization.OptIn)] - public class CreateGuildRequest : IRestRequest + public class CreateGuildParams { - string IRestRequest.Method => "POST"; - string IRestRequest.Endpoint => $"guilds"; - object IRestRequest.Payload => this; - [JsonProperty("name")] public string Name { get; set; } [JsonProperty("region")] diff --git a/src/Discord.Net/API/Rest/CreateGuildRole.cs b/src/Discord.Net/API/Rest/CreateGuildRole.cs deleted file mode 100644 index 367c25465..000000000 --- a/src/Discord.Net/API/Rest/CreateGuildRole.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Discord.Net.Rest; - -namespace Discord.API.Rest -{ - public class CreateGuildRoleRequest : IRestRequest - { - string IRestRequest.Method => "POST"; - string IRestRequest.Endpoint => $"guilds/{GuildId}/roles"; - object IRestRequest.Payload => null; - - public ulong GuildId { get; } - - public CreateGuildRoleRequest(ulong guildId) - { - GuildId = guildId; - } - } -} diff --git a/src/Discord.Net/API/Rest/CreateMessage.cs b/src/Discord.Net/API/Rest/CreateMessage.cs deleted file mode 100644 index 1018a8c66..000000000 --- a/src/Discord.Net/API/Rest/CreateMessage.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Discord.Net.Rest; -using Newtonsoft.Json; - -namespace Discord.API.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class CreateMessageRequest : IRestRequest - { - string IRestRequest.Method => "POST"; - string IRestRequest.Endpoint => $"channels/{ChannelId}/messages"; - object IRestRequest.Payload => this; - - public ulong ChannelId { get; } - - [JsonProperty("content")] - public string Content { get; set; } - [JsonProperty("nonce", NullValueHandling = NullValueHandling.Ignore)] - public string Nonce { get; set; } = null; - [JsonProperty("tts", DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool IsTTS { get; set; } = false; - - public CreateMessageRequest(ulong channelId) - { - ChannelId = channelId; - } - } -} diff --git a/src/Discord.Net/API/Rest/CreateMessageParams.cs b/src/Discord.Net/API/Rest/CreateMessageParams.cs new file mode 100644 index 000000000..6fdc8c2ad --- /dev/null +++ b/src/Discord.Net/API/Rest/CreateMessageParams.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class CreateMessageParams + { + [JsonProperty("content")] + public string Content { get; set; } = ""; + [JsonProperty("nonce", NullValueHandling = NullValueHandling.Ignore)] + public string Nonce { get; set; } = null; + [JsonProperty("tts", DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool IsTTS { get; set; } = false; + } +} diff --git a/src/Discord.Net/API/Rest/DeleteChannel.cs b/src/Discord.Net/API/Rest/DeleteChannel.cs deleted file mode 100644 index fa9b10c10..000000000 --- a/src/Discord.Net/API/Rest/DeleteChannel.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Discord.Net.Rest; - -namespace Discord.API.Rest -{ - public class DeleteChannelRequest : IRestRequest - { - string IRestRequest.Method => "DELETE"; - string IRestRequest.Endpoint => $"channels/{ChannelId}"; - object IRestRequest.Payload => null; - - public ulong ChannelId { get; } - - public DeleteChannelRequest(ulong channelId) - { - ChannelId = channelId; - } - } -} diff --git a/src/Discord.Net/API/Rest/DeleteChannelPermission.cs b/src/Discord.Net/API/Rest/DeleteChannelPermission.cs deleted file mode 100644 index 658388641..000000000 --- a/src/Discord.Net/API/Rest/DeleteChannelPermission.cs +++ /dev/null @@ -1,20 +0,0 @@ -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/Rest/DeleteGuild.cs b/src/Discord.Net/API/Rest/DeleteGuild.cs deleted file mode 100644 index d1a14fbc9..000000000 --- a/src/Discord.Net/API/Rest/DeleteGuild.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Discord.Net.Rest; - -namespace Discord.API.Rest -{ - public class DeleteGuildRequest : IRestRequest - { - string IRestRequest.Method => "DELETE"; - string IRestRequest.Endpoint => $"guilds/{GuildId}"; - object IRestRequest.Payload => null; - - public ulong GuildId { get; } - - public DeleteGuildRequest(ulong guildId) - { - GuildId = guildId; - } - } -} diff --git a/src/Discord.Net/API/Rest/DeleteGuildIntegration.cs b/src/Discord.Net/API/Rest/DeleteGuildIntegration.cs deleted file mode 100644 index b25418c1a..000000000 --- a/src/Discord.Net/API/Rest/DeleteGuildIntegration.cs +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index cbb21eec3..000000000 --- a/src/Discord.Net/API/Rest/DeleteGuildRole.cs +++ /dev/null @@ -1,20 +0,0 @@ -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/Rest/DeleteInvite.cs b/src/Discord.Net/API/Rest/DeleteInvite.cs deleted file mode 100644 index 388255862..000000000 --- a/src/Discord.Net/API/Rest/DeleteInvite.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Discord.Net.Rest; - -namespace Discord.API.Rest -{ - public class DeleteInviteRequest : IRestRequest - { - string IRestRequest.Method => "DELETE"; - string IRestRequest.Endpoint => $"invites/{InviteCode}"; - object IRestRequest.Payload => null; - - public string InviteCode { get; } - - public DeleteInviteRequest(string inviteCode) - { - InviteCode = inviteCode; - } - } -} diff --git a/src/Discord.Net/API/Rest/DeleteMessage.cs b/src/Discord.Net/API/Rest/DeleteMessage.cs deleted file mode 100644 index c9d95deba..000000000 --- a/src/Discord.Net/API/Rest/DeleteMessage.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Discord.Net.Rest; - -namespace Discord.API.Rest -{ - public class DeleteMessageRequest : IRestRequest - { - string IRestRequest.Method => "DELETE"; - string IRestRequest.Endpoint => $"channels/{ChannelId}/messages/{MessageId}"; - object IRestRequest.Payload => null; - - public ulong ChannelId { get; } - public ulong MessageId { get; } - - public DeleteMessageRequest(ulong channelId, ulong messageId) - { - ChannelId = channelId; - MessageId = messageId; - } - } -} diff --git a/src/Discord.Net/API/Rest/DeleteMessagesParam.cs b/src/Discord.Net/API/Rest/DeleteMessagesParam.cs new file mode 100644 index 000000000..8a794499c --- /dev/null +++ b/src/Discord.Net/API/Rest/DeleteMessagesParam.cs @@ -0,0 +1,11 @@ +using Newtonsoft.Json; +using System.Collections.Generic; + +namespace Discord.API.Rest +{ + public class DeleteMessagesParam + { + [JsonProperty("messages")] + public IEnumerable MessageIds { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/GetChannel.cs b/src/Discord.Net/API/Rest/GetChannel.cs deleted file mode 100644 index 12d258836..000000000 --- a/src/Discord.Net/API/Rest/GetChannel.cs +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index 7532fb64f..000000000 --- a/src/Discord.Net/API/Rest/GetChannelInvites.cs +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index a0e6b5afe..000000000 --- a/src/Discord.Net/API/Rest/GetChannelMessages.cs +++ /dev/null @@ -1,34 +0,0 @@ -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/GetChannelMessagesParams.cs b/src/Discord.Net/API/Rest/GetChannelMessagesParams.cs new file mode 100644 index 000000000..ec6e5fe79 --- /dev/null +++ b/src/Discord.Net/API/Rest/GetChannelMessagesParams.cs @@ -0,0 +1,9 @@ +namespace Discord.API.Rest +{ + public class GetChannelMessagesParams + { + public int Limit { get; set; } = DiscordConfig.MaxMessagesPerBatch; + public Direction RelativeDirection { get; set; } = Direction.Before; + public ulong? RelativeMessageId { get; set; } = null; + } +} diff --git a/src/Discord.Net/API/Rest/GetCurrentUser.cs b/src/Discord.Net/API/Rest/GetCurrentUser.cs deleted file mode 100644 index 76bc3e838..000000000 --- a/src/Discord.Net/API/Rest/GetCurrentUser.cs +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 102affaa7..000000000 --- a/src/Discord.Net/API/Rest/GetCurrentUserConnections.cs +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 31cc1edeb..000000000 --- a/src/Discord.Net/API/Rest/GetCurrentUserDMs.cs +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index e3423c3f8..000000000 --- a/src/Discord.Net/API/Rest/GetCurrentUserGuilds.cs +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 3581f9f00..000000000 --- a/src/Discord.Net/API/Rest/GetGateway.cs +++ /dev/null @@ -1,18 +0,0 @@ -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/GatewaySocket/Unconfirmed/Events/Redirect.cs b/src/Discord.Net/API/Rest/GetGatewayResponse.cs similarity index 62% rename from src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Redirect.cs rename to src/Discord.Net/API/Rest/GetGatewayResponse.cs index 180bf574f..48ca524d3 100644 --- a/src/Discord.Net/API/GatewaySocket/Unconfirmed/Events/Redirect.cs +++ b/src/Discord.Net/API/Rest/GetGatewayResponse.cs @@ -1,8 +1,8 @@ using Newtonsoft.Json; -namespace Discord.API.GatewaySocket +namespace Discord.API.Rest { - public class RedirectEvent + 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 deleted file mode 100644 index 2e83d261a..000000000 --- a/src/Discord.Net/API/Rest/GetGuild.cs +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index 73a02b43e..000000000 --- a/src/Discord.Net/API/Rest/GetGuildBans.cs +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index f20e9ec4f..000000000 --- a/src/Discord.Net/API/Rest/GetGuildChannels.cs +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index 0eb67e680..000000000 --- a/src/Discord.Net/API/Rest/GetGuildEmbed.cs +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index ba2b1ce2d..000000000 --- a/src/Discord.Net/API/Rest/GetGuildIntegrations.cs +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index 4a20770b1..000000000 --- a/src/Discord.Net/API/Rest/GetGuildInvites.cs +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index 0dc1d8077..000000000 --- a/src/Discord.Net/API/Rest/GetGuildMember.cs +++ /dev/null @@ -1,20 +0,0 @@ -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/GetGuildMembersParams.cs b/src/Discord.Net/API/Rest/GetGuildMembersParams.cs new file mode 100644 index 000000000..59931e934 --- /dev/null +++ b/src/Discord.Net/API/Rest/GetGuildMembersParams.cs @@ -0,0 +1,8 @@ +namespace Discord.API.Rest +{ + public class GetGuildMembersParams + { + public int? Limit { get; set; } = null; + public int Offset { get; set; } = 0; + } +} diff --git a/src/Discord.Net/API/Rest/GetGuildPruneCount.cs b/src/Discord.Net/API/Rest/GetGuildPruneCount.cs deleted file mode 100644 index 469b5fa01..000000000 --- a/src/Discord.Net/API/Rest/GetGuildPruneCount.cs +++ /dev/null @@ -1,29 +0,0 @@ -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/GetGuildPruneCountResponse.cs b/src/Discord.Net/API/Rest/GetGuildPruneCountResponse.cs new file mode 100644 index 000000000..9b757d14a --- /dev/null +++ b/src/Discord.Net/API/Rest/GetGuildPruneCountResponse.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + 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 deleted file mode 100644 index f8ff0a9b3..000000000 --- a/src/Discord.Net/API/Rest/GetGuildRoles.cs +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index ed631e7e2..000000000 --- a/src/Discord.Net/API/Rest/GetGuildVoiceRegions.cs +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index fccbc79c9..000000000 --- a/src/Discord.Net/API/Rest/GetInvite.cs +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index 1cfeb82be..000000000 --- a/src/Discord.Net/API/Rest/GetUser.cs +++ /dev/null @@ -1,18 +0,0 @@ -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/Rest/GuildPruneParams.cs b/src/Discord.Net/API/Rest/GuildPruneParams.cs new file mode 100644 index 000000000..12a7a11da --- /dev/null +++ b/src/Discord.Net/API/Rest/GuildPruneParams.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class GuildPruneParams + { + [JsonProperty("days")] + public int Days = 30; + } +} diff --git a/src/Discord.Net/API/Rest/LeaveGuild.cs b/src/Discord.Net/API/Rest/LeaveGuild.cs deleted file mode 100644 index a62fdd089..000000000 --- a/src/Discord.Net/API/Rest/LeaveGuild.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Discord.Net.Rest; - -namespace Discord.API.Rest -{ - public class LeaveGuildRequest : IRestRequest - { - string IRestRequest.Method => "DELETE"; - string IRestRequest.Endpoint => $"users/@me/guilds/{GuildId}"; - object IRestRequest.Payload => null; - - public ulong GuildId { get; } - - public LeaveGuildRequest(ulong guildId) - { - GuildId = guildId; - } - } -} diff --git a/src/Discord.Net/API/Rest/ListGuildMembers.cs b/src/Discord.Net/API/Rest/ListGuildMembers.cs deleted file mode 100644 index 4577b8910..000000000 --- a/src/Discord.Net/API/Rest/ListGuildMembers.cs +++ /dev/null @@ -1,24 +0,0 @@ -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/Rest/ModifyChannelPermission.cs b/src/Discord.Net/API/Rest/ModifyChannelPermission.cs deleted file mode 100644 index e38685bb7..000000000 --- a/src/Discord.Net/API/Rest/ModifyChannelPermission.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Discord.Net.Rest; -using Newtonsoft.Json; - -namespace Discord.API.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class ModifyChannelPermissionsRequest : IRestRequest - { - string IRestRequest.Method => "PUT"; - string IRestRequest.Endpoint => $"channels/{ChannelId}/permissions/{TargetId}"; - object IRestRequest.Payload => this; - - public ulong ChannelId { get; } - public ulong TargetId { get; } - - [JsonProperty("allow")] - public uint Allow { get; set; } - [JsonProperty("deny")] - public uint Deny { get; set; } - - public ModifyChannelPermissionsRequest(ulong channelId, ulong targetId) - { - ChannelId = channelId; - TargetId = targetId; - } - } -} diff --git a/src/Discord.Net/API/Rest/ModifyChannelPermissionsParams.cs b/src/Discord.Net/API/Rest/ModifyChannelPermissionsParams.cs new file mode 100644 index 000000000..d02df347d --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyChannelPermissionsParams.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class ModifyChannelPermissionsParams + { + [JsonProperty("allow")] + public uint Allow { get; set; } + [JsonProperty("deny")] + public uint Deny { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/ModifyCurrentUser.cs b/src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs similarity index 62% rename from src/Discord.Net/API/Rest/ModifyCurrentUser.cs rename to src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs index afc1c3b74..f1512536f 100644 --- a/src/Discord.Net/API/Rest/ModifyCurrentUser.cs +++ b/src/Discord.Net/API/Rest/ModifyCurrentUserParams.cs @@ -1,17 +1,11 @@ -using Discord.Net.JsonConverters; -using Discord.Net.Rest; +using Discord.Net.Converters; using Newtonsoft.Json; using System.IO; namespace Discord.API.Rest { - [JsonObject(MemberSerialization.OptIn)] - public class ModifyCurrentUserRequest : IRestRequest + public class ModifyCurrentUserParams { - string IRestRequest.Method => "PATCH"; - string IRestRequest.Endpoint => $"users/@me"; - object IRestRequest.Payload => this; - [JsonProperty("username")] public string Username { get; set; } [JsonProperty("email")] diff --git a/src/Discord.Net/API/Rest/ModifyGuildChannel.cs b/src/Discord.Net/API/Rest/ModifyGuildChannel.cs deleted file mode 100644 index eeb909e84..000000000 --- a/src/Discord.Net/API/Rest/ModifyGuildChannel.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Discord.Net.Rest; -using Newtonsoft.Json; - -namespace Discord.API.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class ModifyGuildChannelRequest : IRestRequest - { - string IRestRequest.Method => "PATCH"; - string IRestRequest.Endpoint => $"channels/{ChannelId}"; - object IRestRequest.Payload => this; - - public ulong ChannelId { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - [JsonProperty("position")] - public int Position { get; set; } - - public ModifyGuildChannelRequest(ulong channelId) - { - ChannelId = channelId; - } - } -} diff --git a/src/Discord.Net/API/Rest/ModifyGuildChannelParams.cs b/src/Discord.Net/API/Rest/ModifyGuildChannelParams.cs new file mode 100644 index 000000000..b82f7b8d2 --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyGuildChannelParams.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class ModifyGuildChannelParams + { + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("position")] + public int Position { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/ModifyGuildChannels.cs b/src/Discord.Net/API/Rest/ModifyGuildChannels.cs deleted file mode 100644 index de9b97b88..000000000 --- a/src/Discord.Net/API/Rest/ModifyGuildChannels.cs +++ /dev/null @@ -1,22 +0,0 @@ -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/ModifyGuildChannelsParams.cs b/src/Discord.Net/API/Rest/ModifyGuildChannelsParams.cs new file mode 100644 index 000000000..73ec46f7d --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyGuildChannelsParams.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class ModifyGuildChannelsParams + { + [JsonProperty("id")] + public ulong Id { get; set; } + [JsonProperty("position")] + public int Position { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/ModifyGuildEmbed.cs b/src/Discord.Net/API/Rest/ModifyGuildEmbed.cs deleted file mode 100644 index c896e5a34..000000000 --- a/src/Discord.Net/API/Rest/ModifyGuildEmbed.cs +++ /dev/null @@ -1,25 +0,0 @@ -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/ModifyGuildEmbedParams.cs b/src/Discord.Net/API/Rest/ModifyGuildEmbedParams.cs new file mode 100644 index 000000000..731497223 --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyGuildEmbedParams.cs @@ -0,0 +1,13 @@ +using Discord.Net.Converters; +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class ModifyGuildEmbedParams + { + [JsonProperty("enabled")] + public bool Enabled { get; set; } + [JsonProperty("channel"), JsonConverter(typeof(UInt64EntityConverter))] + public IVoiceChannel Channel { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/ModifyGuildIntegration.cs b/src/Discord.Net/API/Rest/ModifyGuildIntegration.cs deleted file mode 100644 index b093888da..000000000 --- a/src/Discord.Net/API/Rest/ModifyGuildIntegration.cs +++ /dev/null @@ -1,29 +0,0 @@ -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/Rest/ModifyGuildIntegrationParams.cs b/src/Discord.Net/API/Rest/ModifyGuildIntegrationParams.cs new file mode 100644 index 000000000..9a5e9f81c --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyGuildIntegrationParams.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class ModifyGuildIntegrationParams + { + [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; } + } +} diff --git a/src/Discord.Net/API/Rest/ModifyGuildMember.cs b/src/Discord.Net/API/Rest/ModifyGuildMember.cs deleted file mode 100644 index cdbc1271f..000000000 --- a/src/Discord.Net/API/Rest/ModifyGuildMember.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Discord.Net.Rest; -using Newtonsoft.Json; - -namespace Discord.API.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class ModifyGuildMemberRequest : IRestRequest - { - string IRestRequest.Method => "PATCH"; - string IRestRequest.Endpoint => $"guilds/{GuildId}/members/{UserId}"; - object IRestRequest.Payload => this; - - public ulong GuildId { get; } - public ulong UserId { get; } - - [JsonProperty("roles")] - public ulong[] Roles { get; set; } - [JsonProperty("mute")] - public bool Mute { get; set; } - [JsonProperty("deaf")] - public bool Deaf { get; set; } - [JsonProperty("channel_id")] - public ulong? ChannelId { get; set; } - - public ModifyGuildMemberRequest(ulong guildId, ulong userId) - { - GuildId = guildId; - UserId = userId; - } - } -} diff --git a/src/Discord.Net/API/Rest/ModifyGuildMemberParams.cs b/src/Discord.Net/API/Rest/ModifyGuildMemberParams.cs new file mode 100644 index 000000000..396e0314d --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyGuildMemberParams.cs @@ -0,0 +1,17 @@ +using Discord.Net.Converters; +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class ModifyGuildMemberParams + { + [JsonProperty("roles")] + public ulong[] Roles { get; set; } + [JsonProperty("mute")] + public bool Mute { get; set; } + [JsonProperty("deaf")] + public bool Deaf { get; set; } + [JsonProperty("channel_id"), JsonConverter(typeof(UInt64EntityConverter))] + public IVoiceChannel VoiceChannel { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/ModifyGuild.cs b/src/Discord.Net/API/Rest/ModifyGuildParams.cs similarity index 56% rename from src/Discord.Net/API/Rest/ModifyGuild.cs rename to src/Discord.Net/API/Rest/ModifyGuildParams.cs index 03bf58073..1d5969ab2 100644 --- a/src/Discord.Net/API/Rest/ModifyGuild.cs +++ b/src/Discord.Net/API/Rest/ModifyGuildParams.cs @@ -1,23 +1,15 @@ -using Discord.Net.JsonConverters; -using Discord.Net.Rest; +using Discord.Net.Converters; 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; } - + public class ModifyGuildParams + { [JsonProperty("name")] public string Name { get; set; } - [JsonProperty("region")] - public VoiceRegion Region { get; set; } + [JsonProperty("region"), JsonConverterAttribute(typeof(StringEntityConverter))] + public IVoiceRegion Region { get; set; } [JsonProperty("verification_level")] public int VerificationLevel { get; set; } [JsonProperty("afk_channel_id")] @@ -30,10 +22,5 @@ namespace Discord.API.Rest public GuildMember 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/Rest/ModifyGuildRole.cs b/src/Discord.Net/API/Rest/ModifyGuildRole.cs deleted file mode 100644 index 6d7e09c59..000000000 --- a/src/Discord.Net/API/Rest/ModifyGuildRole.cs +++ /dev/null @@ -1,32 +0,0 @@ -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/ModifyGuildRoleParams.cs b/src/Discord.Net/API/Rest/ModifyGuildRoleParams.cs new file mode 100644 index 000000000..171d9cabe --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyGuildRoleParams.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class ModifyGuildRoleParams + { + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("permissions")] + public uint Permissions { get; set; } + [JsonProperty("position")] + public int Position { get; set; } + [JsonProperty("color")] + public uint Color { get; set; } + [JsonProperty("hoist")] + public bool Hoist { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/ModifyGuildRoles.cs b/src/Discord.Net/API/Rest/ModifyGuildRoles.cs deleted file mode 100644 index 905f51b11..000000000 --- a/src/Discord.Net/API/Rest/ModifyGuildRoles.cs +++ /dev/null @@ -1,21 +0,0 @@ -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/Rest/ModifyGuildRolesParams.cs b/src/Discord.Net/API/Rest/ModifyGuildRolesParams.cs new file mode 100644 index 000000000..7002079d5 --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyGuildRolesParams.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class ModifyGuildRolesParams : ModifyGuildRoleParams + { + [JsonProperty("id")] + public ulong Id { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/ModifyMessage.cs b/src/Discord.Net/API/Rest/ModifyMessage.cs deleted file mode 100644 index 971c8026e..000000000 --- a/src/Discord.Net/API/Rest/ModifyMessage.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Discord.Net.Rest; -using Newtonsoft.Json; - -namespace Discord.API.Rest -{ - [JsonObject(MemberSerialization.OptIn)] - public class ModifyMessageRequest : IRestRequest - { - string IRestRequest.Method => "PATCH"; - string IRestRequest.Endpoint => $"channels/{ChannelId}/messages/{MessageId}"; - object IRestRequest.Payload => this; - - public ulong ChannelId { get; } - public ulong MessageId { get; } - - [JsonProperty("content")] - public string Content { get; set; } = ""; - - public ModifyMessageRequest(ulong channelId, ulong messageId) - { - ChannelId = channelId; - MessageId = messageId; - } - } -} diff --git a/src/Discord.Net/API/Rest/ModifyMessageParams.cs b/src/Discord.Net/API/Rest/ModifyMessageParams.cs new file mode 100644 index 000000000..d3b90b903 --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyMessageParams.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class ModifyMessageParams + { + [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 deleted file mode 100644 index f3d672daf..000000000 --- a/src/Discord.Net/API/Rest/ModifyTextChannel.cs +++ /dev/null @@ -1,16 +0,0 @@ -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/ModifyTextChannelParams.cs b/src/Discord.Net/API/Rest/ModifyTextChannelParams.cs new file mode 100644 index 000000000..cee07e7f1 --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyTextChannelParams.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class ModifyTextChannelParams : ModifyGuildChannelParams + { + [JsonProperty("topic")] + public string Topic { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/ModifyVoiceChannel.cs b/src/Discord.Net/API/Rest/ModifyVoiceChannel.cs deleted file mode 100644 index e8bdfac8f..000000000 --- a/src/Discord.Net/API/Rest/ModifyVoiceChannel.cs +++ /dev/null @@ -1,16 +0,0 @@ -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/ModifyVoiceChannelParams.cs b/src/Discord.Net/API/Rest/ModifyVoiceChannelParams.cs new file mode 100644 index 000000000..1fbae95ac --- /dev/null +++ b/src/Discord.Net/API/Rest/ModifyVoiceChannelParams.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Discord.API.Rest +{ + public class ModifyVoiceChannelParams : ModifyGuildChannelParams + { + [JsonProperty("bitrate")] + public int Bitrate { get; set; } + } +} diff --git a/src/Discord.Net/API/Rest/QueryUser.cs b/src/Discord.Net/API/Rest/QueryUser.cs deleted file mode 100644 index 45a194805..000000000 --- a/src/Discord.Net/API/Rest/QueryUser.cs +++ /dev/null @@ -1,19 +0,0 @@ -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/Rest/RemoveGuildBan.cs b/src/Discord.Net/API/Rest/RemoveGuildBan.cs deleted file mode 100644 index 4f5df1243..000000000 --- a/src/Discord.Net/API/Rest/RemoveGuildBan.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Discord.Net.Rest; - -namespace Discord.API.Rest -{ - public class RemoveGuildBanRequest : IRestRequest - { - string IRestRequest.Method => "DELETE"; - string IRestRequest.Endpoint => $"guilds/{GuildId}/bans/{UserId}"; - object IRestRequest.Payload => null; - - public ulong GuildId { get; } - public ulong UserId { get; } - - public RemoveGuildBanRequest(ulong guildId, ulong userId) - { - GuildId = guildId; - UserId = userId; - } - } -} diff --git a/src/Discord.Net/API/Rest/RemoveGuildMember.cs b/src/Discord.Net/API/Rest/RemoveGuildMember.cs deleted file mode 100644 index a5b39b1db..000000000 --- a/src/Discord.Net/API/Rest/RemoveGuildMember.cs +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index 4c7f0acfa..000000000 --- a/src/Discord.Net/API/Rest/SyncGuildIntegration.cs +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 3c0baa855..000000000 --- a/src/Discord.Net/API/Rest/TriggerTypingIndicator.cs +++ /dev/null @@ -1,18 +0,0 @@ -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/Rest/UploadFile.cs b/src/Discord.Net/API/Rest/UploadFile.cs deleted file mode 100644 index a874eff32..000000000 --- a/src/Discord.Net/API/Rest/UploadFile.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Discord.Net.Rest; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.IO; - -namespace Discord.API.Rest -{ - public class UploadFileRequest : 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; } - - public string Content { get; set; } - public string Nonce { get; set; } - public bool IsTTS { get; set; } - public Stream Stream { get; set; } - public string Filename { get; set; } - - public UploadFileRequest(ulong channelId) - { - ChannelId = channelId; - } - } -} diff --git a/src/Discord.Net/API/Rest/UploadFileParams.cs b/src/Discord.Net/API/Rest/UploadFileParams.cs new file mode 100644 index 000000000..2e1248633 --- /dev/null +++ b/src/Discord.Net/API/Rest/UploadFileParams.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace Discord.API.Rest +{ + public class UploadFileParams + { + public string Content { get; set; } = ""; + public string Nonce { get; set; } = null; + public bool IsTTS { get; set; } = false; + public string Filename { get; set; } = "unknown.dat"; + + public IReadOnlyDictionary ToDictionary() + { + var dic = new Dictionary + { + ["content"] = Content, + ["tts"] = IsTTS.ToString() + }; + if (Nonce != null) + dic.Add("nonce", Nonce); + return dic; + } + } +} diff --git a/src/Discord.Net/API/VoiceSocket/OpCode.cs b/src/Discord.Net/API/VoiceSocket/OpCode.cs deleted file mode 100644 index d9174be22..000000000 --- a/src/Discord.Net/API/VoiceSocket/OpCode.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Discord.API.VoiceSocket -{ - public enum OpCode : byte - { - /// C→S - Used to associate a connection with a token. - Identify = 0, - /// 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, - /// C↔S - Used to keep the connection alive and measure latency. - Heartbeat = 3, - /// C←S - Used to provide an encryption key to the client. - SessionDescription = 4, - /// C↔S - Used to inform that a certain user is speaking. - Speaking = 5 - } -} diff --git a/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/Heartbeat.cs b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/Heartbeat.cs deleted file mode 100644 index f2f356854..000000000 --- a/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/Heartbeat.cs +++ /dev/null @@ -1,10 +0,0 @@ -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 deleted file mode 100644 index 06a63e3c2..000000000 --- a/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/Identify.cs +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index 4aa71b4f3..000000000 --- a/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/SelectProtocol.cs +++ /dev/null @@ -1,28 +0,0 @@ -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/VoiceSocket/Unconfirmed/Commands/SetSpeaking.cs b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/SetSpeaking.cs deleted file mode 100644 index 0476b9a7d..000000000 --- a/src/Discord.Net/API/VoiceSocket/Unconfirmed/Commands/SetSpeaking.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.VoiceSocket -{ - public class SetSpeakingCommand : IWebSocketMessage - { - int IWebSocketMessage.OpCode => (int)OpCode.Speaking; - object IWebSocketMessage.Payload => this; - - [JsonProperty("speaking")] - public bool IsSpeaking { get; set; } - [JsonProperty("delay")] - public int Delay { get; set; } - } -} diff --git a/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/Ready.cs b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/Ready.cs deleted file mode 100644 index 7ba700d96..000000000 --- a/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/Ready.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.VoiceSocket -{ - public class ReadyEvent - { - [JsonProperty("ssrc")] - public uint SSRC { get; set; } - [JsonProperty("port")] - public ushort Port { get; set; } - [JsonProperty("modes")] - public string[] Modes { get; set; } - [JsonProperty("heartbeat_interval")] - public int HeartbeatInterval { get; set; } - } -} diff --git a/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/SessionDescription.cs b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/SessionDescription.cs deleted file mode 100644 index 09bda01c1..000000000 --- a/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/SessionDescription.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.VoiceSocket -{ - public class SessionDescriptionEvent - { - [JsonProperty("secret_key")] - public byte[] SecretKey { get; set; } - [JsonProperty("mode")] - public string Mode { get; set; } - } -} diff --git a/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/Speaking.cs b/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/Speaking.cs deleted file mode 100644 index 0e1271f98..000000000 --- a/src/Discord.Net/API/VoiceSocket/Unconfirmed/Events/Speaking.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Newtonsoft.Json; - -namespace Discord.API.VoiceSocket -{ - public class SpeakingEvent - { - [JsonProperty("user_id")] - public ulong UserId { get; set; } - [JsonProperty("ssrc")] - public uint SSRC { get; set; } - [JsonProperty("speaking")] - public bool IsSpeaking { get; set; } - } -} diff --git a/src/Discord.Net/Discord.Net.Net45.csproj b/src/Discord.Net/Discord.Net.Net45.csproj deleted file mode 100644 index 6a34e8609..000000000 --- a/src/Discord.Net/Discord.Net.Net45.csproj +++ /dev/null @@ -1,303 +0,0 @@ - - - - - - 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 deleted file mode 100644 index 0d36751ed..000000000 --- a/src/Discord.Net/Discord.Net.Net45.project.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "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 deleted file mode 100644 index aad5884f0..000000000 --- a/src/Discord.Net/Discord.Net.Net45.project.lock.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "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.csproj b/src/Discord.Net/Discord.Net.csproj new file mode 100644 index 000000000..d8f98c647 --- /dev/null +++ b/src/Discord.Net/Discord.Net.csproj @@ -0,0 +1,209 @@ + + + + + Debug + AnyCPU + {18F6FE23-73F6-4CA6-BBD9-F0139DC3EE90} + Library + Properties + Discord + Discord.Net + v4.6.1 + 512 + + + + true + full + false + bin\Debug\ + TRACE;DEBUG;__DEMO__,__DEMO_EXPERIMENTAL__ + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Discord.Net/Discord.Net.xproj b/src/Discord.Net/Discord.Net.xproj deleted file mode 100644 index e5ec681b5..000000000 --- a/src/Discord.Net/Discord.Net.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0.25123 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 2c91bdd7-621d-460f-b768-ead106d9ba62 - Discord - ..\..\..\TestBot\artifacts\obj\$(MSBuildProjectName) - ..\..\..\TestBot\artifacts\bin\$(MSBuildProjectName)\ - - - 2.0 - - - True - - - \ No newline at end of file diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs deleted file mode 100644 index 2409a76d2..000000000 --- a/src/Discord.Net/DiscordClient.cs +++ /dev/null @@ -1,341 +0,0 @@ -using Discord.API.Rest; -using Discord.Logging; -using Discord.Net; -using Discord.Net.Rest; -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Discord -{ - public class DiscordClient : IDisposable - { - 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; protected set; } - public SelfUser CurrentUser { get; protected set; } - public bool IsLoggedIn { get; private set; } - - internal CancellationToken CancelToken => _cancelToken.Token; - - public DiscordClient(string token, DiscordConfig config = null) - { - if (token == null) throw new ArgumentNullException(nameof(token)); - - if (config == null) - config = new DiscordConfig(); - - _token = token; - _connectionLock = new SemaphoreSlim(1, 1); - - _restClientProvider = config.RestClientProvider; - UserAgent = $"DiscordBot ({DiscordConfig.LibUrl}, v{DiscordConfig.LibVersion})"; - - _logManager = new LogManager(config.LogLevel); - _logManager.Message += (s, e) => Log(this, e); - _restLogger = _logManager.CreateLogger("Rest"); - } - - public async Task Login() - { - await _connectionLock.WaitAsync().ConfigureAwait(false); - try - { - await LoginInternal().ConfigureAwait(false); - } - finally { _connectionLock.Release(); } - } - protected virtual async Task LoginInternal() - { - if (IsLoggedIn) - await LogoutInternal().ConfigureAwait(false); - - try - { - _cancelToken = new CancellationTokenSource(); - - 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"); - - MessageQueue = new MessageQueue(RestClient, _restLogger); - await MessageQueue.Start(_cancelToken.Token).ConfigureAwait(false); - - var selfResponse = await RestClient.Send(new GetCurrentUserRequest()).ConfigureAwait(false); - var regionsResponse = await RestClient.Send(new GetVoiceRegionsRequest()).ConfigureAwait(false); - - CurrentUser = CreateSelfUser(selfResponse); - VoiceRegions = regionsResponse.Select(x => CreateVoiceRegion(x)).ToImmutableArray(); - - IsLoggedIn = true; - RaiseEvent(LoggedIn); - } - catch (Exception) { await LogoutInternal().ConfigureAwait(false); throw; } - } - - public async Task Logout() - { - _cancelToken?.Cancel(); - await _connectionLock.WaitAsync().ConfigureAwait(false); - try - { - await LogoutInternal().ConfigureAwait(false); - } - finally { _connectionLock.Release(); } - } - protected virtual async Task LogoutInternal() - { - bool wasLoggedIn = IsLoggedIn; - - try { _cancelToken.Cancel(); } catch { } - try { await MessageQueue.Stop().ConfigureAwait(false); } catch { } - - RestClient = null; - MessageQueue = null; - - if (wasLoggedIn) - { - IsLoggedIn = false; - RaiseEvent(LoggedOut); - } - } - - public virtual async Task> GetDMChannels() - { - 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(); - } - public virtual async Task GetInvite(string inviteIdOrXkcd) - { - if (inviteIdOrXkcd == null) throw new ArgumentNullException(nameof(inviteIdOrXkcd)); - - //Remove trailing slash - if (inviteIdOrXkcd.Length > 0 && inviteIdOrXkcd[inviteIdOrXkcd.Length - 1] == '/') - inviteIdOrXkcd = inviteIdOrXkcd.Substring(0, inviteIdOrXkcd.Length - 1); - //Remove leading URL - int index = inviteIdOrXkcd.LastIndexOf('/'); - if (index >= 0) - inviteIdOrXkcd = inviteIdOrXkcd.Substring(index + 1); - - try - { - var response = await RestClient.Send(new GetInviteRequest(inviteIdOrXkcd)).ConfigureAwait(false); - return CreatePublicInvite(response); - } - catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) - { - return null; - } - } - public virtual async Task GetGuild(ulong id) - { - var response = await RestClient.Send(new GetGuildRequest(id)).ConfigureAwait(false); - return CreateGuild(response); - } - public virtual async Task> GetGuilds() - { - 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 = CreateGlobalUser(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) - { - var user = CreateGlobalUser(response[0]); - return user; - } - return null; - } - 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) - { - 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; - } - - 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 response = await RestClient.Send(new CreateGuildRequest - { - Name = name, - Region = region.Id, - Icon = jpegIcon - }).ConfigureAwait(false); - - return CreateGuild(response); - } - - internal virtual DMChannel CreateDMChannel(API.Channel model) - { - var channel = new DMChannel(model.Id, this, 0); - channel.Update(model); - return channel; - } - internal virtual TextChannel CreateTextChannel(Guild guild, API.Channel model) - { - var channel = new TextChannel(model.Id, guild, 0, false); - channel.Update(model); - return channel; - } - internal virtual VoiceChannel CreateVoiceChannel(Guild guild, API.Channel model) - { - var channel = new VoiceChannel(model.Id, guild, false); - channel.Update(model); - return channel; - } - internal virtual GuildInvite CreateGuildInvite(GuildChannel channel, API.InviteMetadata model) - { - var invite = new GuildInvite(model.Code, channel); - invite.Update(model); - return invite; - } - internal virtual PublicInvite CreatePublicInvite(API.Invite model) - { - var invite = new PublicInvite(model.Code, this); - invite.Update(model); - return invite; - } - internal virtual Guild CreateGuild(API.Guild model) - { - var guild = new Guild(model.Id, this); - guild.Update(model); - return guild; - } - internal virtual Message CreateMessage(IMessageChannel channel, IUser user, API.Message model) - { - var msg = new Message(model.Id, channel, user); - msg.Update(model); - return msg; - } - internal virtual Role CreateRole(Guild guild, API.Role model) - { - var role = new Role(model.Id, guild); - role.Update(model); - return role; - } - internal virtual DMUser CreateDMUser(DMChannel channel, API.User model) - { - var user = new DMUser(CreateGlobalUser(model), channel); - user.Update(model); - return user; - } - internal virtual GuildUser CreateGuildUser(Guild guild, API.GuildMember model) - { - var user = new GuildUser(CreateGlobalUser(model.User), guild); - user.Update(model); - return user; - } - internal virtual GuildUser CreateBannedUser(Guild guild, API.User model) - { - var user = new GuildUser(CreateGlobalUser(model), guild); - //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 GlobalUser CreateGlobalUser(API.User model) - { - var user = new GlobalUser(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; - } - - internal virtual void RemoveUser(GlobalUser user) { } - - protected virtual void Dispose(bool disposing) - { - if (!_isDisposed) - { - if (disposing) - { - MessageQueue.Dispose(); - RestClient.Dispose(); - _connectionLock.Dispose(); - } - _isDisposed = true; - } - } - public void Dispose() => Dispose(true); - - 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()); - } -} diff --git a/src/Discord.Net/DiscordConfig.cs b/src/Discord.Net/DiscordConfig.cs index 8598b9f27..e79919d60 100644 --- a/src/Discord.Net/DiscordConfig.cs +++ b/src/Discord.Net/DiscordConfig.cs @@ -1,62 +1,27 @@ -using Discord.Net.Rest; -using Discord.Net.WebSockets; -using System.Reflection; +using System.Reflection; namespace Discord -{ +{ public class DiscordConfig { - public const int MaxMessageSize = 2000; - public const int MaxMessagesPerBatch = 100; + public static string Version { get; } = typeof(DiscordConfig).GetTypeInfo().Assembly?.GetName().Version.ToString(3) ?? "Unknown"; + public static string UserAgent { get; } = $"DiscordBot (https://github.com/RogueException/Discord.Net, v{Version})"; - 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 int GatewayAPIVersion = 3; public const string ClientAPIUrl = "https://discordapp.com/api/"; public const string CDNUrl = "https://cdn.discordapp.com/"; public const string InviteUrl = "https://discord.gg/"; + public const int MaxMessageSize = 2000; + public const int MaxMessagesPerBatch = 100; + public const int MaxUsersPerBatch = 1000; + internal const int RestTimeout = 10000; internal const int MessageQueueInterval = 100; internal const int WebSocketQueueInterval = 100; /// 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.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 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; - - //Engines - - /// 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/DiscordRestClient.cs b/src/Discord.Net/DiscordRestClient.cs new file mode 100644 index 000000000..091e0cb00 --- /dev/null +++ b/src/Discord.Net/DiscordRestClient.cs @@ -0,0 +1,256 @@ +using Discord.API.Rest; +using Discord.Logging; +using Discord.Net.Rest; +using Discord.Rest; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Discord +{ + public sealed class DiscordRestClient : IDiscordClient, IDisposable + { + public event EventHandler Log; + public event EventHandler LoggedIn, LoggedOut; + + private readonly SemaphoreSlim _connectionLock; + private readonly RestClientProvider _restClientProvider; + private readonly LogManager _log; + private CancellationTokenSource _cancelTokenSource; + private bool _isDisposed; + private string _userAgent; + + public bool IsLoggedIn { get; private set; } + internal API.DiscordRawClient BaseClient { get; private set; } + internal SelfUser CurrentUser { get; private set; } + + public DiscordRestClient(DiscordConfig config = null) + { + if (config == null) + config = new DiscordConfig(); + + _restClientProvider = (baseUrl, cancelToken) => new DefaultRestClient(baseUrl, cancelToken); + + _connectionLock = new SemaphoreSlim(1, 1); + _log = new LogManager(config.LogLevel); + _userAgent = DiscordConfig.UserAgent; + + _log.Message += (s,e) => Log.Raise(this, e); + } + + public async Task Login(TokenType tokenType, string token) + { + await _connectionLock.WaitAsync().ConfigureAwait(false); + try + { + await LoginInternal(tokenType, token).ConfigureAwait(false); + } + finally { _connectionLock.Release(); } + } + private async Task LoginInternal(TokenType tokenType, string token) + { + if (IsLoggedIn) + LogoutInternal(); + + try + { + var cancelTokenSource = new CancellationTokenSource(); + + BaseClient = new API.DiscordRawClient(_restClientProvider, cancelTokenSource.Token, tokenType, token); + BaseClient.SentRequest += (s, e) => _log.Verbose($"{e.Method} {e.Endpoint}: {e.Milliseconds} ms"); + + //MessageQueue = new MessageQueue(RestClient, _restLogger); + //await MessageQueue.Start(_cancelTokenSource.Token).ConfigureAwait(false); + + var currentUser = await BaseClient.GetCurrentUser().ConfigureAwait(false); + CurrentUser = new SelfUser(this, currentUser); + + _cancelTokenSource = cancelTokenSource; + IsLoggedIn = true; + LoggedIn.Raise(this); + } + catch { LogoutInternal(); throw; } + } + + public async Task Logout() + { + _cancelTokenSource?.Cancel(); + await _connectionLock.WaitAsync().ConfigureAwait(false); + try + { + LogoutInternal(); + } + finally { _connectionLock.Release(); } + } + private void LogoutInternal() + { + bool wasLoggedIn = IsLoggedIn; + + try { _cancelTokenSource.Cancel(false); } catch { } + + BaseClient = null; + + if (wasLoggedIn) + { + IsLoggedIn = false; + LoggedOut.Raise(this); + } + } + + public async Task> GetConnections() + { + var models = await BaseClient.GetCurrentUserConnections().ConfigureAwait(false); + return models.Select(x => new Connection(x)); + } + + public async Task GetChannel(ulong id) + { + var model = await BaseClient.GetChannel(id).ConfigureAwait(false); + if (model != null) + { + if (model.GuildId != null) + { + var guildModel = await BaseClient.GetGuild(model.GuildId.Value).ConfigureAwait(false); + if (guildModel != null) + { + var guild = new Guild(this, guildModel); + return guild.ToChannel(model); + } + } + else + return new DMChannel(this, model); + } + return null; + } + public async Task> GetDMChannels() + { + var models = await BaseClient.GetCurrentUserDMs().ConfigureAwait(false); + return models.Select(x => new DMChannel(this, x)); + } + + public async Task GetInvite(string inviteIdOrXkcd) + { + var model = await BaseClient.GetInvite(inviteIdOrXkcd).ConfigureAwait(false); + if (model != null) + return new PublicInvite(this, model); + return null; + } + + public async Task GetGuild(ulong id) + { + var model = await BaseClient.GetGuild(id).ConfigureAwait(false); + if (model != null) + return new Guild(this, model); + return null; + } + public async Task GetGuildEmbed(ulong id) + { + var model = await BaseClient.GetGuildEmbed(id).ConfigureAwait(false); + if (model != null) + return new GuildEmbed(this, model); + return null; + } + public async Task> GetGuilds() + { + var models = await BaseClient.GetCurrentUserGuilds().ConfigureAwait(false); + return models.Select(x => new UserGuild(this, x)); + + } + public async Task CreateGuild(string name, IVoiceRegion region, Stream jpegIcon = null) + { + var args = new CreateGuildParams(); + var model = await BaseClient.CreateGuild(args).ConfigureAwait(false); + return new Guild(this, model); + } + + public async Task GetUser(ulong id) + { + var model = await BaseClient.GetUser(id).ConfigureAwait(false); + if (model != null) + return new PublicUser(this, model); + return null; + } + public async Task GetUser(string username, ushort discriminator) + { + var model = await BaseClient.GetUser(username, discriminator).ConfigureAwait(false); + if (model != null) + return new PublicUser(this, model); + return null; + } + public async Task GetCurrentUser() + { + var currentUser = CurrentUser; + if (currentUser == null) + { + var model = await BaseClient.GetCurrentUser().ConfigureAwait(false); + currentUser = new SelfUser(this, model); + CurrentUser = currentUser; + } + return currentUser; + } + public async Task> QueryUsers(string query, int limit) + { + var models = await BaseClient.QueryUsers(query, limit).ConfigureAwait(false); + return models.Select(x => new PublicUser(this, x)); + } + + public async Task> GetVoiceRegions() + { + var models = await BaseClient.GetVoiceRegions().ConfigureAwait(false); + return models.Select(x => new VoiceRegion(x)); + } + public async Task GetVoiceRegion(string id) + { + var models = await BaseClient.GetVoiceRegions().ConfigureAwait(false); + return models.Select(x => new VoiceRegion(x)).Where(x => x.Id == id).FirstOrDefault(); + } + public async Task GetOptimalVoiceRegion() + { + var models = await BaseClient.GetVoiceRegions().ConfigureAwait(false); + return models.Select(x => new VoiceRegion(x)).Where(x => x.IsOptimal).FirstOrDefault(); + } + + void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + _cancelTokenSource.Dispose(); + _isDisposed = true; + } + } + public void Dispose() => Dispose(true); + + API.DiscordRawClient IDiscordClient.BaseClient => BaseClient; + ISelfUser IDiscordClient.CurrentUser => CurrentUser; + + async Task IDiscordClient.GetChannel(ulong id) + => await GetChannel(id).ConfigureAwait(false); + async Task> IDiscordClient.GetDMChannels() + => await GetDMChannels().ConfigureAwait(false); + async Task> IDiscordClient.GetConnections() + => await GetConnections().ConfigureAwait(false); + async Task IDiscordClient.GetInvite(string inviteIdOrXkcd) + => await GetInvite(inviteIdOrXkcd).ConfigureAwait(false); + async Task IDiscordClient.GetGuild(ulong id) + => await GetGuild(id).ConfigureAwait(false); + async Task> IDiscordClient.GetGuilds() + => await GetGuilds().ConfigureAwait(false); + async Task IDiscordClient.CreateGuild(string name, IVoiceRegion region, Stream jpegIcon) + => await CreateGuild(name, region, jpegIcon).ConfigureAwait(false); + async Task IDiscordClient.GetUser(ulong id) + => await GetUser(id).ConfigureAwait(false); + async Task> IDiscordClient.QueryUsers(string query, int limit) + => await QueryUsers(query, limit).ConfigureAwait(false); + async Task> IDiscordClient.GetVoiceRegions() + => await GetVoiceRegions().ConfigureAwait(false); + async Task IDiscordClient.GetVoiceRegion(string id) + => await GetVoiceRegion(id).ConfigureAwait(false); + async Task IDiscordClient.GetOptimalVoiceRegion() + => await GetOptimalVoiceRegion().ConfigureAwait(false); + } +} diff --git a/src/Discord.Net/DiscordSocketClient.cs b/src/Discord.Net/DiscordSocketClient.cs deleted file mode 100644 index 40beb389e..000000000 --- a/src/Discord.Net/DiscordSocketClient.cs +++ /dev/null @@ -1,176 +0,0 @@ -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/Entities/Channels/DMChannel.cs b/src/Discord.Net/Entities/Channels/DMChannel.cs deleted file mode 100644 index c176b9dc0..000000000 --- a/src/Discord.Net/Entities/Channels/DMChannel.cs +++ /dev/null @@ -1,97 +0,0 @@ -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; - - 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 IUser 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 deleted file mode 100644 index aea8c86c0..000000000 --- a/src/Discord.Net/Entities/Channels/GuildChannel.cs +++ /dev/null @@ -1,129 +0,0 @@ -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.GetMembers(); - /// - IEnumerable IChannel.Users => _permissions.GetMembers(); - /// 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); - /// - IUser IChannel.GetUser(ulong id) => GetUser(id); - - /// Gets the permission overwrite for a specific user, or null if one does not exist. - public OverwritePermissions? GetPermissionOverwrite(IUser 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(IUser 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(IUser 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(IUser user) - => _permissions.GetPermissions(user); - internal void UpdatePermissions() - => _permissions.UpdatePermissions(); - internal void UpdatePermissions(IUser 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/src/Discord.Net/Entities/Channels/IChannel.cs b/src/Discord.Net/Entities/Channels/IChannel.cs deleted file mode 100644 index 53dc60f18..000000000 --- a/src/Discord.Net/Entities/Channels/IChannel.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; - -namespace Discord -{ - public interface IChannel : IEntity - { - /// Gets the type flags for this channel. - 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. - IUser GetUser(ulong id); - } -} diff --git a/src/Discord.Net/Entities/Channels/IMessageChannel.cs b/src/Discord.Net/Entities/Channels/IMessageChannel.cs deleted file mode 100644 index 4bb8b5690..000000000 --- a/src/Discord.Net/Entities/Channels/IMessageChannel.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; - -namespace Discord -{ - 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); - /// Gets the last N messages from this text channel. - /// The maximum number of messages to retrieve. - Task> GetMessages(int limit = DiscordConfig.MaxMessagesPerBatch); - /// Gets a collection of messages in this channel. - /// The maximum number of messages to retrieve. - /// The message to start downloading relative to. - /// The direction, from relativeMessageId, to download messages in. - Task> GetMessages(int limit = DiscordConfig.MaxMessagesPerBatch, ulong? relativeMessageId = null, Relative relativeDir = Relative.Before); - - /// Sends a message to this text channel. - Task SendMessage(string text, bool isTTS = false); - /// Sends a file to this text channel, with an optional caption. - Task SendFile(string filePath, string text = null, bool isTTS = false); - /// Sends a file to this text channel, with an optional caption. - 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 TriggerTyping(); - } -} diff --git a/src/Discord.Net/Entities/Channels/TextChannel.cs b/src/Discord.Net/Entities/Channels/TextChannel.cs deleted file mode 100644 index cebb1c573..000000000 --- a/src/Discord.Net/Entities/Channels/TextChannel.cs +++ /dev/null @@ -1,67 +0,0 @@ -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 deleted file mode 100644 index 80fbae797..000000000 --- a/src/Discord.Net/Entities/Channels/VoiceChannel.cs +++ /dev/null @@ -1,39 +0,0 @@ -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/Enums/ChannelType.cs b/src/Discord.Net/Entities/Common/Channels/ChannelType.cs similarity index 100% rename from src/Discord.Net/Enums/ChannelType.cs rename to src/Discord.Net/Entities/Common/Channels/ChannelType.cs diff --git a/src/Discord.Net/Entities/Common/Channels/IChannel.cs b/src/Discord.Net/Entities/Common/Channels/IChannel.cs new file mode 100644 index 000000000..9540f4d26 --- /dev/null +++ b/src/Discord.Net/Entities/Common/Channels/IChannel.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Discord +{ + public interface IChannel : ISnowflakeEntity + { + /// Gets a collection of all users in this channel. + Task> GetUsers(); + /// Gets a user in this channel with the provided id. + Task GetUser(ulong id); + } +} diff --git a/src/Discord.Net/Entities/Common/Channels/IDMChannel.cs b/src/Discord.Net/Entities/Common/Channels/IDMChannel.cs new file mode 100644 index 000000000..f6b53a91f --- /dev/null +++ b/src/Discord.Net/Entities/Common/Channels/IDMChannel.cs @@ -0,0 +1,13 @@ +using System.Threading.Tasks; + +namespace Discord +{ + public interface IDMChannel : IMessageChannel, IUpdateable + { + /// Gets the recipient of all messages in this channel. + IDMUser Recipient { get; } + + /// Closes this private channel, removing it from your channel list. + Task Close(); + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Common/Channels/IGuildChannel.cs b/src/Discord.Net/Entities/Common/Channels/IGuildChannel.cs new file mode 100644 index 000000000..456f6931e --- /dev/null +++ b/src/Discord.Net/Entities/Common/Channels/IGuildChannel.cs @@ -0,0 +1,51 @@ +using Discord.API.Rest; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Discord +{ + public interface IGuildChannel : IChannel, IDeletable, IUpdateable + { + /// Gets the name of this channel. + string Name { get; } + /// Gets the position of this channel in the guild's channel list, relative to others of the same type. + int Position { get; } + + /// Gets the guild this channel is a member of. + IGuild Guild { get; } + + /// Creates a new invite to this channel. + /// The 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. + Task CreateInvite(int? maxAge = 1800, int? maxUses = default(int?), bool isTemporary = false, bool withXkcd = false); + /// Returns a collection of all invites to this channel. + Task> GetInvites(); + + /// Gets a collection of permission overwrites for this channel. + IReadOnlyDictionary PermissionOverwrites { get; } + + /// Modifies this guild channel. + Task Modify(Action func); + + /// Gets the permission overwrite for a specific role, or null if one does not exist. + OverwritePermissions? GetPermissionOverwrite(IRole role); + /// Gets the permission overwrite for a specific user, or null if one does not exist. + OverwritePermissions? GetPermissionOverwrite(IUser user); + /// Removes the permission overwrite for the given role, if one exists. + Task RemovePermissionOverwrite(IRole role); + /// Removes the permission overwrite for the given user, if one exists. + Task RemovePermissionOverwrite(IUser user); + /// Adds or updates the permission overwrite for the given role. + Task AddPermissionOverwrite(IRole role, OverwritePermissions permissions); + /// Adds or updates the permission overwrite for the given user. + Task AddPermissionOverwrite(IUser user, OverwritePermissions permissions); + + /// Gets a collection of all users in this channel. + new Task> GetUsers(); + /// Gets a user in this channel with the provided id. + new Task GetUser(ulong id); + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Common/Channels/IMessageChannel.cs b/src/Discord.Net/Entities/Common/Channels/IMessageChannel.cs new file mode 100644 index 000000000..c2a10f30b --- /dev/null +++ b/src/Discord.Net/Entities/Common/Channels/IMessageChannel.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace Discord +{ + public interface IMessageChannel : IChannel + { + /// Gets the message in this message channel with the given id, or null if none was found. + Task GetMessage(ulong id); + /// Gets the last N messages from this message channel. + Task> GetMessages(int limit = DiscordConfig.MaxMessagesPerBatch); + /// Gets a collection of messages in this channel. + Task> GetMessages(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch); + + /// Sends a message to this text channel. + Task SendMessage(string text, bool isTTS = false); + /// Sends a file to this text channel, with an optional caption. + Task SendFile(string filePath, string text = null, bool isTTS = false); + /// Sends a file to this text channel, with an optional caption. + Task SendFile(Stream stream, string filename, string text = null, bool isTTS = false); + + /// Bulk deletes multiple messages. + Task DeleteMessages(IEnumerable messages); + + /// Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds. + Task TriggerTyping(); + } +} diff --git a/src/Discord.Net/Entities/Common/Channels/ITextChannel.cs b/src/Discord.Net/Entities/Common/Channels/ITextChannel.cs new file mode 100644 index 000000000..fe0578e57 --- /dev/null +++ b/src/Discord.Net/Entities/Common/Channels/ITextChannel.cs @@ -0,0 +1,15 @@ +using Discord.API.Rest; +using System; +using System.Threading.Tasks; + +namespace Discord +{ + public interface ITextChannel : IMessageChannel, IMentionable, IGuildChannel + { + /// Gets the current topic for this text channel. + string Topic { get; } + + /// Modifies this text channel. + Task Modify(Action func); + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Common/Channels/IVoiceChannel.cs b/src/Discord.Net/Entities/Common/Channels/IVoiceChannel.cs new file mode 100644 index 000000000..baa2d741f --- /dev/null +++ b/src/Discord.Net/Entities/Common/Channels/IVoiceChannel.cs @@ -0,0 +1,15 @@ +using Discord.API.Rest; +using System; +using System.Threading.Tasks; + +namespace Discord +{ + public interface IVoiceChannel : IGuildChannel + { + /// Gets the bitrate, in bits per second, clients in this voice channel are requested to use. + int Bitrate { get; } + + /// Modifies this voice channel. + Task Modify(Action func); + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Emoji.cs b/src/Discord.Net/Entities/Common/Guilds/Emoji.cs similarity index 62% rename from src/Discord.Net/Entities/Emoji.cs rename to src/Discord.Net/Entities/Common/Guilds/Emoji.cs index 66010d968..9f4478e74 100644 --- a/src/Discord.Net/Entities/Emoji.cs +++ b/src/Discord.Net/Entities/Common/Guilds/Emoji.cs @@ -1,28 +1,23 @@ 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; } + public IImmutableList RoleIds { get; } - internal Emoji(Model model, Guild guild) + internal Emoji(Model model) { Id = model.Id; - _guild = guild; - Name = model.Name; IsManaged = model.Managed; RequireColons = model.RequireColons; - _roles = model.Roles.Select(x => guild.GetRole(x)).ToImmutableArray(); + RoleIds = ImmutableArray.Create(model.Roles); } } } diff --git a/src/Discord.Net/Entities/Common/Guilds/IGuild.cs b/src/Discord.Net/Entities/Common/Guilds/IGuild.cs new file mode 100644 index 000000000..2c3d8a3c8 --- /dev/null +++ b/src/Discord.Net/Entities/Common/Guilds/IGuild.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Discord.API.Rest; + +namespace Discord +{ + public interface IGuild : IDeletable, ISnowflakeEntity, IUpdateable + { + /// 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. + int AFKTimeout { get; } + /// Returns true if this guild is embeddable (e.g. widget) + bool IsEmbeddable { get; } + /// Gets the name of this guild. + string Name { get; } + int VerificationLevel { get; } + + /// Gets the id of the AFK voice channel for this guild if set, or null if not. + ulong? AFKChannelId { get; } + /// Gets the id of the the default channel for this guild. + ulong DefaultChannelId { get; } + /// Gets the id of the embed channel for this guild if set, or null if not. + ulong? EmbedChannelId { get; } + /// Gets the id of the role containing all users in this guild. + ulong EveryoneRoleId { get; } + /// Gets the id of the user that created this guild. + ulong OwnerId { get; } + /// Gets the id of the server region hosting this guild's voice channels. + string VoiceRegionId { get; } + + /// Returns the url to this server's icon, or null if one is not set. + string IconUrl { get; } + /// Returns the url to this server's splash image, or null if one is not set. + string SplashUrl { get; } + + /// Gets a collection of all custom emojis for this guild. + IEnumerable Emojis { get; } + /// Gets a collection of all extra features added to this guild. + IEnumerable Features { get; } + + /// Modifies this guild. + Task Modify(Action func); + /// Modifies this guild's embed. + Task ModifyEmbed(Action func); + /// Bulk modifies the channels of this guild. + Task ModifyChannels(IEnumerable args); + /// Bulk modifies the roles of this guild. + Task ModifyRoles(IEnumerable args); + /// Leaves this guild. If you are the owner, use Delete instead. + Task Leave(); + + /// Gets a collection of all users banned on this guild. + Task> GetBans(); + /// Bans the provided user from this guild and optionally prunes their recent messages. + Task AddBan(IUser user, int pruneDays = 0); + /// Bans the provided user id from this guild and optionally prunes their recent messages. + Task AddBan(ulong userId, int pruneDays = 0); + /// Unbans the provided user if it is currently banned. + Task RemoveBan(IUser user); + /// Unbans the provided user id if it is currently banned. + Task RemoveBan(ulong userId); + + /// Gets a collection of all channels in this guild. + Task> GetChannels(); + /// Gets the channel in this guild with the provided id, or null if not found. + Task GetChannel(ulong id); + /// Creates a new text channel. + Task CreateTextChannel(string name); + /// Creates a new voice channel. + Task CreateVoiceChannel(string name); + + /// Gets a collection of all invites to this guild. + Task> GetInvites(); + /// Creates a new invite to this guild. + /// The 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. + Task CreateInvite(int? maxAge = 1800, int? maxUses = default(int?), bool isTemporary = false, bool withXkcd = false); + + /// Gets a collection of all roles in this guild. + Task> GetRoles(); + /// Gets the role in this guild with the provided id, or null if not found. + Task GetRole(ulong id); + /// Creates a new role. + Task CreateRole(string name, GuildPermissions? permissions = null, Color? color = null, bool isHoisted = false); + + /// Gets a collection of all users in this guild. + Task> GetUsers(); + /// Gets the user in this guild with the provided id, or null if not found. + Task GetUser(ulong id); + Task PruneUsers(int days = 30, bool simulate = false); + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Common/Guilds/IGuildEmbed.cs b/src/Discord.Net/Entities/Common/Guilds/IGuildEmbed.cs new file mode 100644 index 000000000..0ad23039f --- /dev/null +++ b/src/Discord.Net/Entities/Common/Guilds/IGuildEmbed.cs @@ -0,0 +1,8 @@ +namespace Discord +{ + public interface IGuildEmbed : ISnowflakeEntity + { + bool IsEnabled { get; } + ulong? ChannelId { get; } + } +} diff --git a/src/Discord.Net/Entities/Common/Guilds/IGuildIntegration.cs b/src/Discord.Net/Entities/Common/Guilds/IGuildIntegration.cs new file mode 100644 index 000000000..0252382fd --- /dev/null +++ b/src/Discord.Net/Entities/Common/Guilds/IGuildIntegration.cs @@ -0,0 +1,21 @@ +using System; + +namespace Discord +{ + public interface IGuildIntegration + { + ulong Id { get; } + string Name { get; } + string Type { get; } + bool IsEnabled { get; } + bool IsSyncing { get; } + ulong ExpireBehavior { get; } + ulong ExpireGracePeriod { get; } + DateTime SyncedAt { get; } + + IGuild Guild { get; } + IUser User { get; } + IRole Role { get; } + IIntegrationAccount Account { get; } + } +} diff --git a/src/Discord.Net/Entities/Common/Guilds/IIntegrationAccount.cs b/src/Discord.Net/Entities/Common/Guilds/IIntegrationAccount.cs new file mode 100644 index 000000000..7e5052c1b --- /dev/null +++ b/src/Discord.Net/Entities/Common/Guilds/IIntegrationAccount.cs @@ -0,0 +1,7 @@ +namespace Discord +{ + public interface IIntegrationAccount : IEntity + { + string Name { get; } + } +} diff --git a/src/Discord.Net/Entities/Common/Guilds/IUserGuild.cs b/src/Discord.Net/Entities/Common/Guilds/IUserGuild.cs new file mode 100644 index 000000000..962602e4a --- /dev/null +++ b/src/Discord.Net/Entities/Common/Guilds/IUserGuild.cs @@ -0,0 +1,14 @@ +namespace Discord +{ + public interface IUserGuild : IDeletable, ISnowflakeEntity + { + /// Gets the name of this guild. + string Name { get; } + /// Returns the url to this server's icon, or null if one is not set. + string IconUrl { get; } + /// Returns true if the current user owns this guild. + bool IsOwner { get; } + /// Returns the current user's permissions for this guild. + GuildPermissions Permissions { get; } + } +} diff --git a/src/Discord.Net/Entities/Common/Guilds/IVoiceRegion.cs b/src/Discord.Net/Entities/Common/Guilds/IVoiceRegion.cs new file mode 100644 index 000000000..22fa6432c --- /dev/null +++ b/src/Discord.Net/Entities/Common/Guilds/IVoiceRegion.cs @@ -0,0 +1,16 @@ +namespace Discord +{ + public interface IVoiceRegion : IEntity + { + /// Gets the name of this voice region. + string Name { get; } + /// Returns true if this voice region is exclusive to VIP accounts. + bool IsVip { get; } + /// Returns true if this voice region is the closest to your machine. + bool IsOptimal { get; } + /// Gets an example hostname for this voice region. + string SampleHostname { get; } + /// Gets an example port for this voice region. + int SamplePort { get; } + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Common/IDeletable.cs b/src/Discord.Net/Entities/Common/IDeletable.cs new file mode 100644 index 000000000..98887b571 --- /dev/null +++ b/src/Discord.Net/Entities/Common/IDeletable.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace Discord +{ + public interface IDeletable + { + /// Deletes this object and all its children. + Task Delete(); + } +} diff --git a/src/Discord.Net/Entities/Common/IEntity.cs b/src/Discord.Net/Entities/Common/IEntity.cs new file mode 100644 index 000000000..80f345bda --- /dev/null +++ b/src/Discord.Net/Entities/Common/IEntity.cs @@ -0,0 +1,8 @@ +namespace Discord +{ + public interface IEntity + { + /// Gets the unique identifier for this object. + TId Id { get; } + } +} diff --git a/src/Discord.Net/Entities/IMentionable.cs b/src/Discord.Net/Entities/Common/IMentionable.cs similarity index 53% rename from src/Discord.Net/Entities/IMentionable.cs rename to src/Discord.Net/Entities/Common/IMentionable.cs index 0a4bf439c..abccc4480 100644 --- a/src/Discord.Net/Entities/IMentionable.cs +++ b/src/Discord.Net/Entities/Common/IMentionable.cs @@ -2,6 +2,7 @@ { public interface IMentionable { + /// Returns a special string used to mention this object. string Mention { get; } } } diff --git a/src/Discord.Net/Entities/Common/ISnowflakeEntity.cs b/src/Discord.Net/Entities/Common/ISnowflakeEntity.cs new file mode 100644 index 000000000..0f0f890cd --- /dev/null +++ b/src/Discord.Net/Entities/Common/ISnowflakeEntity.cs @@ -0,0 +1,10 @@ +using System; + +namespace Discord +{ + public interface ISnowflakeEntity : IEntity + { + /// Gets when this object was created. + DateTime CreatedAt { get; } + } +} diff --git a/src/Discord.Net/Entities/Common/IUpdateable.cs b/src/Discord.Net/Entities/Common/IUpdateable.cs new file mode 100644 index 000000000..eeb31bf88 --- /dev/null +++ b/src/Discord.Net/Entities/Common/IUpdateable.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace Discord +{ + public interface IUpdateable + { + /// Ensures this objects's cached properties reflect its current state on the Discord server. + Task Update(); + } +} diff --git a/src/Discord.Net/Entities/Common/Invites/IGuildInvite.cs b/src/Discord.Net/Entities/Common/Invites/IGuildInvite.cs new file mode 100644 index 000000000..25e6d0e80 --- /dev/null +++ b/src/Discord.Net/Entities/Common/Invites/IGuildInvite.cs @@ -0,0 +1,19 @@ +namespace Discord +{ + public interface IGuildInvite : IDeletable, IInvite + { + /// Returns true if this invite was revoked. + bool IsRevoked { get; } + /// Returns true if users accepting this invite will be removed from the guild when they log off. + bool IsTemporary { get; } + /// Gets the time (in seconds) until the invite expires, or null if it never expires. + int? MaxAge { get; } + /// Gets the max amount of times this invite may be used, or null if there is no limit. + int? MaxUses { get; } + /// Gets the amount of times this invite has been used. + int Uses { get; } + + /// Gets the guild this invite is linked to. + IGuild Guild { get; } + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Common/Invites/IInvite.cs b/src/Discord.Net/Entities/Common/Invites/IInvite.cs new file mode 100644 index 000000000..d0eb8888c --- /dev/null +++ b/src/Discord.Net/Entities/Common/Invites/IInvite.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; + +namespace Discord +{ + public interface IInvite : IEntity + { + /// Gets the unique identifier for this invite. + string Code { get; } + /// Gets the url used to accept this invite, using Code. + string Url { get; } + /// Gets the human-readable identifier for this code. + string XkcdCode { get; } + /// Gets the url used to accept this invite, using XkcdCode. + string XkcdUrl { get; } + + /// Gets the id of the the channel this invite is linked to. + ulong ChannelId { get; } + /// Gets the id of the guild this invite is linked to. + ulong GuildId { get; } + + /// Accepts this invite and joins the target server. This will fail on bot accounts. + Task Accept(); + } +} diff --git a/src/Discord.Net/Entities/Common/Invites/IPublicInvite.cs b/src/Discord.Net/Entities/Common/Invites/IPublicInvite.cs new file mode 100644 index 000000000..1d518bd0a --- /dev/null +++ b/src/Discord.Net/Entities/Common/Invites/IPublicInvite.cs @@ -0,0 +1,10 @@ +namespace Discord +{ + public interface IPublicInvite : IInvite + { + /// Gets the name of the the channel this invite is linked to. + string ChannelName { get; } + /// Gets the name of the guild this invite is linked to. + string GuildName { get; } + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Attachment.cs b/src/Discord.Net/Entities/Common/Messages/Attachment.cs similarity index 100% rename from src/Discord.Net/Entities/Attachment.cs rename to src/Discord.Net/Entities/Common/Messages/Attachment.cs diff --git a/src/Discord.Net/Enums/Relative.cs b/src/Discord.Net/Entities/Common/Messages/Direction.cs similarity index 72% rename from src/Discord.Net/Enums/Relative.cs rename to src/Discord.Net/Entities/Common/Messages/Direction.cs index aade047d1..c849146ff 100644 --- a/src/Discord.Net/Enums/Relative.cs +++ b/src/Discord.Net/Entities/Common/Messages/Direction.cs @@ -1,6 +1,6 @@ namespace Discord { - public enum Relative + public enum Direction { Before, After diff --git a/src/Discord.Net/Entities/Embed.cs b/src/Discord.Net/Entities/Common/Messages/Embed.cs similarity index 100% rename from src/Discord.Net/Entities/Embed.cs rename to src/Discord.Net/Entities/Common/Messages/Embed.cs diff --git a/src/Discord.Net/Entities/EmbedProvider.cs b/src/Discord.Net/Entities/Common/Messages/EmbedProvider.cs similarity index 100% rename from src/Discord.Net/Entities/EmbedProvider.cs rename to src/Discord.Net/Entities/Common/Messages/EmbedProvider.cs diff --git a/src/Discord.Net/Entities/EmbedThumbnail.cs b/src/Discord.Net/Entities/Common/Messages/EmbedThumbnail.cs similarity index 100% rename from src/Discord.Net/Entities/EmbedThumbnail.cs rename to src/Discord.Net/Entities/Common/Messages/EmbedThumbnail.cs diff --git a/src/Discord.Net/Entities/Common/Messages/IMessage.cs b/src/Discord.Net/Entities/Common/Messages/IMessage.cs new file mode 100644 index 000000000..54f2df870 --- /dev/null +++ b/src/Discord.Net/Entities/Common/Messages/IMessage.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Discord.API.Rest; + +namespace Discord +{ + public interface IMessage : IDeletable, ISnowflakeEntity + { + /// Gets the time of this message's last edit, if any. + DateTime? EditedTimestamp { get; } + /// Returns true if this message originated from the logged-in account. + bool IsAuthor { get; } + /// Returns true if this message was sent as a text-to-speech message. + bool IsTTS { get; } + /// Returns the original, unprocessed text for this message. + string RawText { get; } + /// Returns the text for this message after mention processing. + string Text { get; } + /// Gets the time this message was sent. + DateTime Timestamp { get; } //TODO: Is this different from IHasSnowflake.CreatedAt? + + /// Gets the channel this message was sent to. + IMessageChannel Channel { get; } + /// Gets the author of this message. + IUser Author { get; } + + /// Returns a collection of all attachments included in this message. + IReadOnlyList Attachments { get; } + /// Returns a collection of all embeds included in this message. + IReadOnlyList Embeds { get; } + /// Returns a collection of channel ids mentioned in this message. + IReadOnlyList MentionedChannelIds { get; } + /// Returns a collection of role ids mentioned in this message. + IReadOnlyList MentionedRoleIds { get; } + /// Returns a collection of user ids mentioned in this message. + IReadOnlyList MentionedUsers { get; } + + /// Modifies this message. + Task Modify(Action func); + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Common/Permissions/ChannelPermission.cs b/src/Discord.Net/Entities/Common/Permissions/ChannelPermission.cs new file mode 100644 index 000000000..df8b88480 --- /dev/null +++ b/src/Discord.Net/Entities/Common/Permissions/ChannelPermission.cs @@ -0,0 +1,36 @@ +namespace Discord +{ + internal enum ChannelPermission : byte + { + //General + CreateInstantInvite = 0, + //KickMembers = 1, + //BanMembers = 2, + //ManagePermissions = 3, + ManageChannel = 4, + //ManageGuild = 5, + + //Text + ReadMessages = 10, + SendMessages = 11, + SendTTSMessages = 12, + ManageMessages = 13, + EmbedLinks = 14, + AttachFiles = 15, + ReadMessageHistory = 16, + MentionEveryone = 17, + + //Voice + Connect = 20, + Speak = 21, + MuteMembers = 22, + DeafenMembers = 23, + MoveMembers = 24, + UseVAD = 25, + + //Nicknames + //ChangeNickname = 26, + //ManageNicknames = 27, + ManagePermissions = 28, + } +} diff --git a/src/Discord.Net/Entities/Common/Permissions/ChannelPermissions.cs b/src/Discord.Net/Entities/Common/Permissions/ChannelPermissions.cs new file mode 100644 index 000000000..ffcc403cf --- /dev/null +++ b/src/Discord.Net/Entities/Common/Permissions/ChannelPermissions.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; + +namespace Discord +{ + public struct ChannelPermissions + { + private static ChannelPermissions _allDM { get; } = new ChannelPermissions(0b000100_000000_0011111111_0000011001); + private static ChannelPermissions _allText { get; } = new ChannelPermissions(0b000000_000000_0001110011_0000000000); + private static ChannelPermissions _allVoice { get; } = new ChannelPermissions(0b000100_111111_0000000000_0000011001); + + /// 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(IChannel channel) + { + switch (channel) + { + case ITextChannel _: return _allText; + case IVoiceChannel _: return _allVoice; + case IDMChannel _: return _allDM; + default: + throw new ArgumentException("Unknown channel type", nameof(channel)); + } + } + + /// 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 => PermissionUtilities.GetValue(RawValue, ChannelPermission.CreateInstantInvite); + /// If True, a user may create, delete and modify this channel. + public bool ManageChannel => PermissionUtilities.GetValue(RawValue, ChannelPermission.ManageChannel); + + /// If True, a user may join channels. + public bool ReadMessages => PermissionUtilities.GetValue(RawValue, ChannelPermission.ReadMessages); + /// If True, a user may send messages. + public bool SendMessages => PermissionUtilities.GetValue(RawValue, ChannelPermission.SendMessages); + /// If True, a user may send text-to-speech messages. + public bool SendTTSMessages => PermissionUtilities.GetValue(RawValue, ChannelPermission.SendTTSMessages); + /// If True, a user may delete messages. + public bool ManageMessages => PermissionUtilities.GetValue(RawValue, ChannelPermission.ManageMessages); + /// If True, Discord will auto-embed links sent by this user. + public bool EmbedLinks => PermissionUtilities.GetValue(RawValue, ChannelPermission.EmbedLinks); + /// If True, a user may send files. + public bool AttachFiles => PermissionUtilities.GetValue(RawValue, ChannelPermission.AttachFiles); + /// If True, a user may read previous messages. + public bool ReadMessageHistory => PermissionUtilities.GetValue(RawValue, ChannelPermission.ReadMessageHistory); + /// If True, a user may mention @everyone. + public bool MentionEveryone => PermissionUtilities.GetValue(RawValue, ChannelPermission.MentionEveryone); + + /// If True, a user may connect to a voice channel. + public bool Connect => PermissionUtilities.GetValue(RawValue, ChannelPermission.Connect); + /// If True, a user may speak in a voice channel. + public bool Speak => PermissionUtilities.GetValue(RawValue, ChannelPermission.Speak); + /// If True, a user may mute users. + public bool MuteMembers => PermissionUtilities.GetValue(RawValue, ChannelPermission.MuteMembers); + /// If True, a user may deafen users. + public bool DeafenMembers => PermissionUtilities.GetValue(RawValue, ChannelPermission.DeafenMembers); + /// If True, a user may move other users between voice channels. + public bool MoveMembers => PermissionUtilities.GetValue(RawValue, ChannelPermission.MoveMembers); + /// If True, a user may use voice-activity-detection rather than push-to-talk. + public bool UseVAD => PermissionUtilities.GetValue(RawValue, ChannelPermission.UseVAD); + + /// If True, a user may adjust permissions. This also implictly grants all other permissions. + public bool ManagePermissions => PermissionUtilities.GetValue(RawValue, ChannelPermission.ManagePermissions); + + /// Creates a new ChannelPermissions with the provided packed value. + public ChannelPermissions(uint rawValue) { RawValue = rawValue; } + + private ChannelPermissions(uint initialValue, bool? createInstantInvite = 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, bool? managePermissions = null) + { + uint value = initialValue; + + PermissionUtilities.SetValue(ref value, createInstantInvite, ChannelPermission.CreateInstantInvite); + PermissionUtilities.SetValue(ref value, manageChannel, ChannelPermission.ManageChannel); + PermissionUtilities.SetValue(ref value, readMessages, ChannelPermission.ReadMessages); + PermissionUtilities.SetValue(ref value, sendMessages, ChannelPermission.SendMessages); + PermissionUtilities.SetValue(ref value, sendTTSMessages, ChannelPermission.SendTTSMessages); + PermissionUtilities.SetValue(ref value, manageMessages, ChannelPermission.ManageMessages); + PermissionUtilities.SetValue(ref value, embedLinks, ChannelPermission.EmbedLinks); + PermissionUtilities.SetValue(ref value, attachFiles, ChannelPermission.AttachFiles); + PermissionUtilities.SetValue(ref value, readMessageHistory, ChannelPermission.ReadMessageHistory); + PermissionUtilities.SetValue(ref value, mentionEveryone, ChannelPermission.MentionEveryone); + PermissionUtilities.SetValue(ref value, connect, ChannelPermission.Connect); + PermissionUtilities.SetValue(ref value, speak, ChannelPermission.Speak); + PermissionUtilities.SetValue(ref value, muteMembers, ChannelPermission.MuteMembers); + PermissionUtilities.SetValue(ref value, deafenMembers, ChannelPermission.DeafenMembers); + PermissionUtilities.SetValue(ref value, moveMembers, ChannelPermission.MoveMembers); + PermissionUtilities.SetValue(ref value, useVoiceActivation, ChannelPermission.UseVAD); + PermissionUtilities.SetValue(ref value, managePermissions, ChannelPermission.ManagePermissions); + + RawValue = value; + } + + /// Creates a new ChannelPermissions with the provided permissions. + public ChannelPermissions(bool createInstantInvite = 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, bool managePermissions = false) + : this(0, createInstantInvite, manageChannel, readMessages, sendMessages, sendTTSMessages, manageMessages, + embedLinks, attachFiles, readMessageHistory, mentionEveryone, connect, speak, muteMembers, deafenMembers, + moveMembers, useVoiceActivation, managePermissions) { } + + /// Creates a new ChannelPermissions from this one, changing the provided non-null permissions. + public ChannelPermissions Modify(bool? createInstantInvite = 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, bool? managePermissions = null) + => new ChannelPermissions(RawValue, createInstantInvite, manageChannel, readMessages, sendMessages, sendTTSMessages, manageMessages, + embedLinks, attachFiles, readMessageHistory, mentionEveryone, connect, speak, muteMembers, deafenMembers, + moveMembers, useVoiceActivation, managePermissions); + + /// + public override string ToString() + { + var perms = new List(); + int x = 1; + for (byte i = 0; i < 32; i++, x <<= 1) + { + if ((RawValue & x) != 0) + { + if (Enum.IsDefined(typeof(ChannelPermission), i)) + perms.Add($"{(ChannelPermission)i}"); + } + } + return string.Join(", ", perms); + } + } +} diff --git a/src/Discord.Net/Enums/PermissionBits.cs b/src/Discord.Net/Entities/Common/Permissions/GuildPermission.cs similarity index 70% rename from src/Discord.Net/Enums/PermissionBits.cs rename to src/Discord.Net/Entities/Common/Permissions/GuildPermission.cs index 513d7da16..497b78726 100644 --- a/src/Discord.Net/Enums/PermissionBits.cs +++ b/src/Discord.Net/Entities/Common/Permissions/GuildPermission.cs @@ -1,13 +1,13 @@ namespace Discord { - internal enum PermissionBit : byte + internal enum GuildPermission : byte { //General CreateInstantInvite = 0, KickMembers = 1, BanMembers = 2, - ManageRolesOrPermissions = 3, - ManageChannel = 4, + Administrator = 3, + ManageChannels = 4, ManageGuild = 5, //Text @@ -26,6 +26,11 @@ MuteMembers = 22, DeafenMembers = 23, MoveMembers = 24, - UseVAD = 25 + UseVAD = 25, + + //Nicknames + ChangeNickname = 26, + ManageNicknames = 27, + ManageRoles = 28, } } diff --git a/src/Discord.Net/Entities/Common/Permissions/GuildPermissions.cs b/src/Discord.Net/Entities/Common/Permissions/GuildPermissions.cs new file mode 100644 index 000000000..55b62599e --- /dev/null +++ b/src/Discord.Net/Entities/Common/Permissions/GuildPermissions.cs @@ -0,0 +1,145 @@ +using System.Collections.Generic; + +namespace Discord +{ + public struct GuildPermissions + { + /// Gets a blank GuildPermissions that grants no permissions. + public static readonly GuildPermissions None = new GuildPermissions(); + /// Gets a GuildPermissions that grants all permissions. + public static readonly GuildPermissions All = new GuildPermissions(0b000111_111111_0011111111_0000111111); + + /// 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 => PermissionUtilities.GetValue(RawValue, GuildPermission.CreateInstantInvite); + /// If True, a user may ban users from the guild. + public bool BanMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.BanMembers); + /// If True, a user may kick users from the guild. + public bool KickMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.KickMembers); + /// If True, a user is granted all permissions, and cannot have them revoked via channel permissions. + public bool Administrator => PermissionUtilities.GetValue(RawValue, GuildPermission.Administrator); + /// If True, a user may create, delete and modify channels. + public bool ManageChannels => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageChannels); + /// If True, a user may adjust guild properties. + public bool ManageGuild => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageGuild); + + /// If True, a user may join channels. + public bool ReadMessages => PermissionUtilities.GetValue(RawValue, GuildPermission.ReadMessages); + /// If True, a user may send messages. + public bool SendMessages => PermissionUtilities.GetValue(RawValue, GuildPermission.SendMessages); + /// If True, a user may send text-to-speech messages. + public bool SendTTSMessages => PermissionUtilities.GetValue(RawValue, GuildPermission.SendTTSMessages); + /// If True, a user may delete messages. + public bool ManageMessages => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageMessages); + /// If True, Discord will auto-embed links sent by this user. + public bool EmbedLinks => PermissionUtilities.GetValue(RawValue, GuildPermission.EmbedLinks); + /// If True, a user may send files. + public bool AttachFiles => PermissionUtilities.GetValue(RawValue, GuildPermission.AttachFiles); + /// If True, a user may read previous messages. + public bool ReadMessageHistory => PermissionUtilities.GetValue(RawValue, GuildPermission.ReadMessageHistory); + /// If True, a user may mention @everyone. + public bool MentionEveryone => PermissionUtilities.GetValue(RawValue, GuildPermission.MentionEveryone); + + /// If True, a user may connect to a voice channel. + public bool Connect => PermissionUtilities.GetValue(RawValue, GuildPermission.Connect); + /// If True, a user may speak in a voice channel. + public bool Speak => PermissionUtilities.GetValue(RawValue, GuildPermission.Speak); + /// If True, a user may mute users. + public bool MuteMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.MuteMembers); + /// If True, a user may deafen users. + public bool DeafenMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.DeafenMembers); + /// If True, a user may move other users between voice channels. + public bool MoveMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.MoveMembers); + /// If True, a user may use voice-activity-detection rather than push-to-talk. + public bool UseVAD => PermissionUtilities.GetValue(RawValue, GuildPermission.UseVAD); + + /// If True, a user may change their own nickname. + public bool ChangeNickname => PermissionUtilities.GetValue(RawValue, GuildPermission.ChangeNickname); + /// If True, a user may change the nickname of other users. + public bool ManageNicknames => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageNicknames); + /// If True, a user may adjust roles. + public bool ManageRoles => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageRoles); + + /// Creates a new GuildPermissions with the provided packed value. + public GuildPermissions(uint rawValue) { RawValue = rawValue; } + + private GuildPermissions(uint initialValue, bool? createInstantInvite = null, bool? kickMembers = null, + bool? banMembers = null, bool? administrator = 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, bool? changeNickname = null, bool? manageNicknames = null, + bool? manageRoles = null) + { + uint value = initialValue; + + PermissionUtilities.SetValue(ref value, createInstantInvite, GuildPermission.CreateInstantInvite); + PermissionUtilities.SetValue(ref value, banMembers, GuildPermission.BanMembers); + PermissionUtilities.SetValue(ref value, kickMembers, GuildPermission.KickMembers); + PermissionUtilities.SetValue(ref value, administrator, GuildPermission.Administrator); + PermissionUtilities.SetValue(ref value, manageChannel, GuildPermission.ManageChannels); + PermissionUtilities.SetValue(ref value, manageGuild, GuildPermission.ManageGuild); + PermissionUtilities.SetValue(ref value, readMessages, GuildPermission.ReadMessages); + PermissionUtilities.SetValue(ref value, sendMessages, GuildPermission.SendMessages); + PermissionUtilities.SetValue(ref value, sendTTSMessages, GuildPermission.SendTTSMessages); + PermissionUtilities.SetValue(ref value, manageMessages, GuildPermission.ManageMessages); + PermissionUtilities.SetValue(ref value, embedLinks, GuildPermission.EmbedLinks); + PermissionUtilities.SetValue(ref value, attachFiles, GuildPermission.AttachFiles); + PermissionUtilities.SetValue(ref value, readMessageHistory, GuildPermission.ReadMessageHistory); + PermissionUtilities.SetValue(ref value, mentionEveryone, GuildPermission.MentionEveryone); + PermissionUtilities.SetValue(ref value, connect, GuildPermission.Connect); + PermissionUtilities.SetValue(ref value, speak, GuildPermission.Speak); + PermissionUtilities.SetValue(ref value, muteMembers, GuildPermission.MuteMembers); + PermissionUtilities.SetValue(ref value, deafenMembers, GuildPermission.DeafenMembers); + PermissionUtilities.SetValue(ref value, moveMembers, GuildPermission.MoveMembers); + PermissionUtilities.SetValue(ref value, useVoiceActivation, GuildPermission.UseVAD); + PermissionUtilities.SetValue(ref value, changeNickname, GuildPermission.ChangeNickname); + PermissionUtilities.SetValue(ref value, manageNicknames, GuildPermission.ManageNicknames); + PermissionUtilities.SetValue(ref value, manageRoles, GuildPermission.ManageRoles); + + RawValue = value; + } + + /// Creates a new GuildPermissions with the provided permissions. + public GuildPermissions(bool createInstantInvite = false, bool kickMembers = false, + bool banMembers = false, bool administrator = false, bool manageChannels = 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, bool? changeNickname = false, bool? manageNicknames = false, + bool manageRoles = false) + : this(0, createInstantInvite, manageRoles, kickMembers, banMembers, manageChannels, manageGuild, readMessages, + sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, mentionEveryone, connect, speak, muteMembers, deafenMembers, + moveMembers, useVoiceActivation, changeNickname, manageNicknames, manageRoles) { } + + /// Creates a new GuildPermissions from this one, changing the provided non-null permissions. + public GuildPermissions Modify(bool? createInstantInvite = null, bool? kickMembers = null, + bool? banMembers = null, bool? administrator = null, bool? manageChannels = 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, bool? changeNickname = null, bool? manageNicknames = null, + bool? manageRoles = null) + => new GuildPermissions(RawValue, createInstantInvite, manageRoles, kickMembers, banMembers, manageChannels, manageGuild, readMessages, + sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, mentionEveryone, connect, speak, muteMembers, deafenMembers, + moveMembers, useVoiceActivation, changeNickname, manageNicknames, manageRoles); + + /// + public override string ToString() + { + var perms = new List(); + int x = 1; + for (byte i = 0; i < 32; i++, x <<= 1) + { + if ((RawValue & x) != 0) + { + if (System.Enum.IsDefined(typeof(GuildPermission), i)) + perms.Add($"{(GuildPermission)i}"); + } + } + return string.Join(", ", perms); + } + } +} diff --git a/src/Discord.Net/Entities/Permissions/Overwrite.cs b/src/Discord.Net/Entities/Common/Permissions/Overwrite.cs similarity index 100% rename from src/Discord.Net/Entities/Permissions/Overwrite.cs rename to src/Discord.Net/Entities/Common/Permissions/Overwrite.cs diff --git a/src/Discord.Net/Entities/Common/Permissions/OverwritePermissions.cs b/src/Discord.Net/Entities/Common/Permissions/OverwritePermissions.cs new file mode 100644 index 000000000..735b17dcf --- /dev/null +++ b/src/Discord.Net/Entities/Common/Permissions/OverwritePermissions.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; + +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(IChannel channel) + => new OverwritePermissions(ChannelPermissions.All(channel).RawValue, 0); + /// Gets a OverwritePermissions that denies all permissions for a given channelType. + public static OverwritePermissions DenyAll(IChannel channel) + => new OverwritePermissions(0, ChannelPermissions.All(channel).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 => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.CreateInstantInvite); + /// If True, a user may create, delete and modify this channel. + public PermValue ManageChannel => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ManageChannel); + /// If True, a user may join channels. + public PermValue ReadMessages => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ReadMessages); + /// If True, a user may send messages. + public PermValue SendMessages => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.SendMessages); + /// If True, a user may send text-to-speech messages. + public PermValue SendTTSMessages => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.SendTTSMessages); + /// If True, a user may delete messages. + public PermValue ManageMessages => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ManageMessages); + /// If True, Discord will auto-embed links sent by this user. + public PermValue EmbedLinks => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.EmbedLinks); + /// If True, a user may send files. + public PermValue AttachFiles => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.AttachFiles); + /// If True, a user may read previous messages. + public PermValue ReadMessageHistory => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ReadMessageHistory); + /// If True, a user may mention @everyone. + public PermValue MentionEveryone => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.MentionEveryone); + + /// If True, a user may connect to a voice channel. + public PermValue Connect => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.Connect); + /// If True, a user may speak in a voice channel. + public PermValue Speak => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.Speak); + /// If True, a user may mute users. + public PermValue MuteMembers => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.MuteMembers); + /// If True, a user may deafen users. + public PermValue DeafenMembers => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.DeafenMembers); + /// If True, a user may move other users between voice channels. + public PermValue MoveMembers => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.MoveMembers); + /// If True, a user may use voice-activity-detection rather than push-to-talk. + public PermValue UseVAD => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.UseVAD); + + /// If True, a user may adjust permissions. This also implictly grants all other permissions. + public PermValue ManagePermissions => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ManagePermissions); + + /// 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? 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, PermValue? managePermissions = null) + { + PermissionUtilities.SetValue(ref allowValue, ref denyValue, createInstantInvite, ChannelPermission.CreateInstantInvite); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, manageChannel, ChannelPermission.ManageChannel); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, readMessages, ChannelPermission.ReadMessages); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, sendMessages, ChannelPermission.SendMessages); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, sendTTSMessages, ChannelPermission.SendTTSMessages); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, manageMessages, ChannelPermission.ManageMessages); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, embedLinks, ChannelPermission.EmbedLinks); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, attachFiles, ChannelPermission.AttachFiles); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, readMessageHistory, ChannelPermission.ReadMessageHistory); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, mentionEveryone, ChannelPermission.MentionEveryone); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, connect, ChannelPermission.Connect); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, speak, ChannelPermission.Speak); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, muteMembers, ChannelPermission.MuteMembers); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, deafenMembers, ChannelPermission.DeafenMembers); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, moveMembers, ChannelPermission.MoveMembers); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, useVoiceActivation, ChannelPermission.UseVAD); + PermissionUtilities.SetValue(ref allowValue, ref denyValue, managePermissions, ChannelPermission.ManagePermissions); + + AllowValue = allowValue; + DenyValue = denyValue; + } + + /// Creates a new ChannelPermissions with the provided permissions. + public OverwritePermissions(PermValue createInstantInvite = 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, PermValue managePermissions = PermValue.Inherit) + : this(0, 0, createInstantInvite, manageChannel, readMessages, sendMessages, sendTTSMessages, manageMessages, + embedLinks, attachFiles, readMessageHistory, mentionEveryone, connect, speak, muteMembers, deafenMembers, + moveMembers, useVoiceActivation, managePermissions) { } + + /// Creates a new OverwritePermissions from this one, changing the provided non-null permissions. + public OverwritePermissions Modify(PermValue? createInstantInvite = 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, PermValue? managePermissions = null) + => new OverwritePermissions(AllowValue, DenyValue, createInstantInvite, manageChannel, readMessages, sendMessages, sendTTSMessages, manageMessages, + embedLinks, attachFiles, readMessageHistory, mentionEveryone, connect, speak, muteMembers, deafenMembers, + moveMembers, useVoiceActivation, managePermissions); + + /// + public override string ToString() + { + var perms = new List(); + int x = 1; + for (byte i = 0; i < 32; i++, x <<= 1) + { + if ((AllowValue & x) != 0) + { + if (Enum.IsDefined(typeof(GuildPermission), i)) + perms.Add($"+{(GuildPermission)i}"); + } + else if ((DenyValue & x) != 0) + { + if (Enum.IsDefined(typeof(GuildPermission), i)) + perms.Add($"-{(GuildPermission)i}"); + } + } + return string.Join(", ", perms); + } + } +} diff --git a/src/Discord.Net/Enums/PermValue.cs b/src/Discord.Net/Entities/Common/Permissions/PermValue.cs similarity index 100% rename from src/Discord.Net/Enums/PermValue.cs rename to src/Discord.Net/Entities/Common/Permissions/PermValue.cs diff --git a/src/Discord.Net/Enums/PermissionTarget.cs b/src/Discord.Net/Entities/Common/Permissions/PermissionTarget.cs similarity index 100% rename from src/Discord.Net/Enums/PermissionTarget.cs rename to src/Discord.Net/Entities/Common/Permissions/PermissionTarget.cs diff --git a/src/Discord.Net/Entities/Common/Permissions/PermissionUtilities.cs b/src/Discord.Net/Entities/Common/Permissions/PermissionUtilities.cs new file mode 100644 index 000000000..66ad57374 --- /dev/null +++ b/src/Discord.Net/Entities/Common/Permissions/PermissionUtilities.cs @@ -0,0 +1,87 @@ +using System.Runtime.CompilerServices; + +namespace Discord +{ + internal static class PermissionUtilities + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PermValue GetValue(uint allow, uint deny, ChannelPermission bit) + => GetValue(allow, deny, (byte)bit); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PermValue GetValue(uint allow, uint deny, GuildPermission bit) + => GetValue(allow, deny, (byte)bit); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PermValue GetValue(uint allow, uint deny, byte bit) + { + if (HasBit(allow, bit)) + return PermValue.Allow; + else if (HasBit(deny, bit)) + return PermValue.Deny; + else + return PermValue.Inherit; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool GetValue(uint value, ChannelPermission bit) + => GetValue(value, (byte)bit); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool GetValue(uint value, GuildPermission bit) + => GetValue(value, (byte)bit); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool GetValue(uint value, byte bit) => HasBit(value, bit); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SetValue(ref uint rawValue, bool? value, ChannelPermission bit) + => SetValue(ref rawValue, value, (byte)bit); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SetValue(ref uint rawValue, bool? value, GuildPermission bit) + => SetValue(ref rawValue, value, (byte)bit); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SetValue(ref uint rawValue, bool? value, byte 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, ChannelPermission bit) + => SetValue(ref allow, ref deny, value, (byte)bit); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SetValue(ref uint allow, ref uint deny, PermValue? value, GuildPermission bit) + => SetValue(ref allow, ref deny, value, (byte)bit); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SetValue(ref uint allow, ref uint deny, PermValue? value, byte 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 bool HasBit(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/Color.cs b/src/Discord.Net/Entities/Common/Roles/Color.cs similarity index 97% rename from src/Discord.Net/Entities/Color.cs rename to src/Discord.Net/Entities/Common/Roles/Color.cs index 3aecc39ac..8e65b52e3 100644 --- a/src/Discord.Net/Entities/Color.cs +++ b/src/Discord.Net/Entities/Common/Roles/Color.cs @@ -1,6 +1,6 @@ namespace Discord { - public class Color + public struct Color { /// Gets the default user color value. public static readonly Color Default = new Color(0); diff --git a/src/Discord.Net/Entities/Common/Roles/IRole.cs b/src/Discord.Net/Entities/Common/Roles/IRole.cs new file mode 100644 index 000000000..e51769790 --- /dev/null +++ b/src/Discord.Net/Entities/Common/Roles/IRole.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Discord.API.Rest; + +namespace Discord +{ + public interface IRole : IDeletable, ISnowflakeEntity + { + /// Gets the color given to users of this role. + Color Color { get; } + /// Returns true if users of this role are separated in the user list. + bool IsHoisted { get; } + /// Returns true if this role is automatically managed by the Discord server. + bool IsManaged { get; } + /// Gets the name of this role. + string Name { get; } + /// Gets the permissions granted to members of this role. + GuildPermissions Permissions { get; } + /// Gets this role's position relative to other roles in the same guild. + int Position { get; } + + /// Gets the id of the guild owning this role. + ulong GuildId { get; } + + /// Modifies this role. + Task Modify(Action func); + + /// Returns a collection of all users that have been assigned this role. + Task> GetUsers(); + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Common/Users/IConnection.cs b/src/Discord.Net/Entities/Common/Users/IConnection.cs new file mode 100644 index 000000000..3c9b5a79e --- /dev/null +++ b/src/Discord.Net/Entities/Common/Users/IConnection.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace Discord +{ + public interface IConnection + { + string Id { get; } + string Type { get; } + string Name { get; } + bool IsRevoked { get; } + + IEnumerable Integrations { get; } + } +} diff --git a/src/Discord.Net/Entities/Common/Users/IDMUser.cs b/src/Discord.Net/Entities/Common/Users/IDMUser.cs new file mode 100644 index 000000000..e8fdd1f19 --- /dev/null +++ b/src/Discord.Net/Entities/Common/Users/IDMUser.cs @@ -0,0 +1,8 @@ +namespace Discord +{ + public interface IDMUser : IUser + { + /// Gets the private channel with this user. + IDMChannel Channel { get; } + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Common/Users/IGuildUser.cs b/src/Discord.Net/Entities/Common/Users/IGuildUser.cs new file mode 100644 index 000000000..222530ecd --- /dev/null +++ b/src/Discord.Net/Entities/Common/Users/IGuildUser.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Discord.API.Rest; + +namespace Discord +{ + /// A Guild-User pairing. + public interface IGuildUser : IUpdateable, IUser + { + /// Returns true if the guild has deafened this user. + bool IsDeaf { get; } + /// Returns true if the guild has muted this user. + bool IsMute { get; } + /// Gets when this user joined this guild. + DateTime JoinedAt { get; } + /// Gets the nickname for this user. + string Nickname { get; } + + /// Gets the guild for this guild-user pair. + IGuild Guild { get; } + /// Returns a collection of the roles this user is a member of in this guild, including the guild's @everyone role. + IReadOnlyList Roles { get; } + /// Gets the id of the voice channel this user is currently in, if any. + ulong? VoiceChannelId { get; } + + /// Gets the guild-level permissions granted to this user by their roles. + GuildPermissions GetGuildPermissions(); + /// Gets the channel-level permissions granted to this user for a given channel. + ChannelPermissions GetPermissions(IGuildChannel channel); + + /// Return true if this user has the provided role. + bool HasRole(IRole role); + + /// Kicks this user from this guild. + Task Kick(); + /// Modifies this user's properties in this guild. + Task Modify(Action func); + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Common/Users/ISelfUser.cs b/src/Discord.Net/Entities/Common/Users/ISelfUser.cs new file mode 100644 index 000000000..d6e7c7718 --- /dev/null +++ b/src/Discord.Net/Entities/Common/Users/ISelfUser.cs @@ -0,0 +1,16 @@ +using Discord.API.Rest; +using System; +using System.Threading.Tasks; + +namespace Discord +{ + public interface ISelfUser : IUser, IUpdateable + { + /// Gets the email associated with this user. + string Email { get; } + /// Returns true if this user's email has been verified. + bool IsVerified { get; } + + Task Modify(Action func); + } +} \ No newline at end of file diff --git a/src/Discord.Net/Entities/Common/Users/IUser.cs b/src/Discord.Net/Entities/Common/Users/IUser.cs new file mode 100644 index 000000000..550c53e8b --- /dev/null +++ b/src/Discord.Net/Entities/Common/Users/IUser.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; + +namespace Discord +{ + public interface IUser : ISnowflakeEntity, IMentionable + { + /// Gets the url to this user's avatar. + string AvatarUrl { get; } + /// Gets the game this user is currently playing, if any. + string CurrentGame { get; } + /// Gets the per-username unique id for this user. + ushort Discriminator { get; } + /// Returns true if this user is a bot account. + bool IsBot { get; } + /// Gets the current status of this user. + UserStatus Status { get; } + /// Gets the username for this user. + string Username { get; } + + /// Returns a private message channel to this user, creating one if it does not already exist. + Task CreateDMChannel(); + } +} diff --git a/src/Discord.Net/Entities/Users/VoiceState.cs b/src/Discord.Net/Entities/Common/Users/IVoiceState.cs.old similarity index 98% rename from src/Discord.Net/Entities/Users/VoiceState.cs rename to src/Discord.Net/Entities/Common/Users/IVoiceState.cs.old index 740a54bba..5044126a9 100644 --- a/src/Discord.Net/Entities/Users/VoiceState.cs +++ b/src/Discord.Net/Entities/Common/Users/IVoiceState.cs.old @@ -1,7 +1,7 @@ /*using System; using Model = Discord.API.MemberVoiceState; -namespace Discord +namespace Discord.WebSocket { public class VoiceState { diff --git a/src/Discord.Net/Enums/UserStatus.cs b/src/Discord.Net/Entities/Common/Users/UserStatus.cs similarity index 100% rename from src/Discord.Net/Enums/UserStatus.cs rename to src/Discord.Net/Entities/Common/Users/UserStatus.cs diff --git a/src/Discord.Net/Entities/Guild.cs b/src/Discord.Net/Entities/Guild.cs deleted file mode 100644 index 57ec95071..000000000 --- a/src/Discord.Net/Entities/Guild.cs +++ /dev/null @@ -1,383 +0,0 @@ -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 CreateGuildChannelRequest(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 CreateGuildChannelRequest(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 CreateGuildRoleRequest(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.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 deleted file mode 100644 index 13058e621..000000000 --- a/src/Discord.Net/Entities/Helpers/InviteManager.cs +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 9555c5391..000000000 --- a/src/Discord.Net/Entities/Helpers/MentionHelper.cs +++ /dev/null @@ -1,111 +0,0 @@ -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(IUser 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 deleted file mode 100644 index 0d5ddb62f..000000000 --- a/src/Discord.Net/Entities/Helpers/MessageManager.cs +++ /dev/null @@ -1,174 +0,0 @@ -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, IUser 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 UploadFileRequest(_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 deleted file mode 100644 index 1646f8ea1..000000000 --- a/src/Discord.Net/Entities/Helpers/PermissionManager.cs +++ /dev/null @@ -1,289 +0,0 @@ -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(IUser 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(IUser 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(IUser 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(IUser 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(IUser 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(IUser user) - { - var permissions = new ChannelPermissions(); - ResolvePermissions(user, ref permissions); - return permissions; - } - private ChannelPermissions ResolvePermissions(GuildUser user) - { - var permissions = new ChannelPermissions(); - ResolvePermissions(user, ref permissions); - return permissions; - } - public bool ResolvePermissions(IUser user, ref ChannelPermissions permissions) - { - if (user == null) throw new ArgumentNullException(nameof(user)); - - GuildUser guildUser = _channel.GetUser(user.Id); - if (guildUser == null) - { - permissions = ChannelPermissions.None; - return false; - } - else - return ResolvePermissions(user, ref permissions); - } - private bool ResolvePermissions(GuildUser user, ref ChannelPermissions permissions) - { - uint newPermissions = 0; - - uint mask = ChannelPermissions.All(_channel.Type).RawValue; - if (user == 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.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.VoiceChannel == _channel) - return user; - } - } - return null; - } - public IEnumerable GetMembers() - { - 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.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 deleted file mode 100644 index e14d5e210..000000000 --- a/src/Discord.Net/Entities/Helpers/PermissionsHelper.cs +++ /dev/null @@ -1,61 +0,0 @@ -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/IEntity.cs b/src/Discord.Net/Entities/IEntity.cs deleted file mode 100644 index ecdde0a56..000000000 --- a/src/Discord.Net/Entities/IEntity.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Threading.Tasks; - -namespace Discord -{ - public interface IEntity : IEntity - { - /// Gets the unique identifier for this object. - TId Id { get; } - } - - public interface IEntity - { - /// Gets the DiscordClient that manages this object. - DiscordClient Discord { get; } - - /// Downloads the latest values and updates this object. - Task Update(); - } -} diff --git a/src/Discord.Net/Entities/Invites/GuildInvite.cs b/src/Discord.Net/Entities/Invites/GuildInvite.cs deleted file mode 100644 index d4387c744..000000000 --- a/src/Discord.Net/Entities/Invites/GuildInvite.cs +++ /dev/null @@ -1,71 +0,0 @@ -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 deleted file mode 100644 index 8765cdc93..000000000 --- a/src/Discord.Net/Entities/Invites/IInvite.cs +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index 2dbd07ec5..000000000 --- a/src/Discord.Net/Entities/Invites/Invite.cs +++ /dev/null @@ -1,48 +0,0 @@ -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 deleted file mode 100644 index 45ac5b084..000000000 --- a/src/Discord.Net/Entities/Invites/InviteChannel.cs +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index 0354bd282..000000000 --- a/src/Discord.Net/Entities/Invites/InviteGuild.cs +++ /dev/null @@ -1,16 +0,0 @@ -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/Message.cs b/src/Discord.Net/Entities/Message.cs deleted file mode 100644 index 09c5d57cb..000000000 --- a/src/Discord.Net/Entities/Message.cs +++ /dev/null @@ -1,139 +0,0 @@ -using Discord.API.Rest; -using Discord.Net; -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using Model = Discord.API.Message; - -namespace Discord -{ - public class Message : IEntity - { - //TODO: Docstrings - - /// - public ulong Id { get; } - public IMessageChannel Channel { get; } - public IUser User { get; } - - public bool IsTTS { get; private set; } - public string RawText { get; private set; } - public string Text { get; private set; } - public DateTime Timestamp { get; private 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; } - - public DiscordClient Discord => Channel.Discord; - public bool IsAuthor => User.Id == Discord.CurrentUser.Id; - - internal Message(ulong id, IMessageChannel channel, IUser user) - { - Id = id; - Channel = channel; - User = user; - } - - internal void Update(Model model) - { - var channel = Channel; - bool isPublic = channel.Type != ChannelType.DM; - - IsTTS = model.IsTextToSpeech; - Timestamp = model.Timestamp; - EditedTimestamp = model.EditedTimestamp; - RawText = model.Content; - - if (model.Attachments.Length > 0) - { - 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); - } - else - Attachments = ImmutableArray.Empty; - - 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; - - 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 (model.IsMentioningEveryone && isPublic) - MentionedRoles = ImmutableArray.Create((channel as GuildChannel).Guild.EveryoneRole); - else - MentionedRoles = ImmutableArray.Empty; - - string text = model.Content; - if (isPublic) - { - var publicChannel = channel as GuildChannel; - var mentionedChannels = ImmutableArray.CreateBuilder(); - text = MentionHelper.CleanUserMentions(publicChannel, text); - text = MentionHelper.CleanChannelMentions(publicChannel, text, mentionedChannels); - MentionedChannels = mentionedChannels.ToImmutable(); - } - else - MentionedChannels = ImmutableArray.Empty; - Text = text; - } - - /// Returns true if the logged-in user was mentioned. - public bool IsMentioningMe(bool includeRoles = false) - { - var me = Channel.GetCurrentUser() as GuildUser; - if (me != null) - { - if (includeRoles) - return MentionedUsers.Contains(me) || MentionedRoles.Any(x => me.HasRole(x)); - else - return MentionedUsers.Contains(me); - } - return false; - } - - public async Task Modify(Action func) - { - if (func != null) throw new NullReferenceException(nameof(func)); - - var req = new ModifyMessageRequest(Channel.Id, Id); - func(req); - await Discord.RestClient.Send(req).ConfigureAwait(false); - } - - public Task Update() { throw new NotSupportedException(); } //TODO: Not supported yet - - /// Deletes this message. - public async Task Delete() - { - try { await Discord.RestClient.Send(new DeleteMessageRequest(Channel.Id, Id)).ConfigureAwait(false); } - catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } - } - } -} diff --git a/src/Discord.Net/Entities/Permissions/ChannelPermissions.cs b/src/Discord.Net/Entities/Permissions/ChannelPermissions.cs deleted file mode 100644 index 076f33230..000000000 --- a/src/Discord.Net/Entities/Permissions/ChannelPermissions.cs +++ /dev/null @@ -1,122 +0,0 @@ -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-activity-detection rather than push-to-talk. - public bool UseVAD => PermissionsHelper.GetValue(RawValue, PermissionBit.UseVAD); - - /// 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.UseVAD); - - 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 deleted file mode 100644 index 081232e25..000000000 --- a/src/Discord.Net/Entities/Permissions/GuildPermissions.cs +++ /dev/null @@ -1,119 +0,0 @@ -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-activity-detection rather than push-to-talk. - public bool UseVAD => PermissionsHelper.GetValue(RawValue, PermissionBit.UseVAD); - - /// 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.UseVAD); - - 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/OverwritePermissions.cs b/src/Discord.Net/Entities/Permissions/OverwritePermissions.cs deleted file mode 100644 index dc6512e7b..000000000 --- a/src/Discord.Net/Entities/Permissions/OverwritePermissions.cs +++ /dev/null @@ -1,113 +0,0 @@ -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-activity-detection rather than push-to-talk. - public PermValue UseVAD => PermissionsHelper.GetValue(AllowValue, DenyValue, PermissionBit.UseVAD); - - /// 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.UseVAD); - - 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/Rest/Channels/DMChannel.cs b/src/Discord.Net/Entities/Rest/Channels/DMChannel.cs new file mode 100644 index 000000000..48510acbc --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Channels/DMChannel.cs @@ -0,0 +1,146 @@ +using Discord.API.Rest; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.Channel; + +namespace Discord.Rest +{ + public class DMChannel : IDMChannel + { + /// + public ulong Id { get; } + internal DiscordRestClient Discord { get; } + + /// + public DMUser Recipient { get; private set; } + + /// + public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); + /// + public IEnumerable Users => ImmutableArray.Create(Discord.CurrentUser, Recipient); + + internal DMChannel(DiscordRestClient discord, Model model) + { + Id = model.Id; + Discord = discord; + + Update(model); + } + private void Update(Model model) + { + if (Recipient == null) + Recipient = new DMUser(this, model.Recipient); + else + Recipient.Update(model.Recipient); + } + + /// + public IUser GetUser(ulong id) + { + if (id == Recipient.Id) + return Recipient; + else if (id == Discord.CurrentUser.Id) + return Discord.CurrentUser; + else + return null; + } + public IEnumerable GetUsers() + { + return ImmutableArray.Create(Discord.CurrentUser, Recipient); + } + + /// + public async Task> GetMessages(int limit = DiscordConfig.MaxMessagesPerBatch) + { + var args = new GetChannelMessagesParams { Limit = limit }; + var models = await Discord.BaseClient.GetChannelMessages(Id, args).ConfigureAwait(false); + return models.Select(x => new Message(this, x)); + } + /// + public async Task> GetMessages(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) + { + var args = new GetChannelMessagesParams { Limit = limit }; + var models = await Discord.BaseClient.GetChannelMessages(Id, args).ConfigureAwait(false); + return models.Select(x => new Message(this, x)); + } + + /// + public async Task SendMessage(string text, bool isTTS = false) + { + var args = new CreateMessageParams { Content = text, IsTTS = isTTS }; + var model = await Discord.BaseClient.CreateMessage(Id, args).ConfigureAwait(false); + return new Message(this, model); + } + /// + public async Task SendFile(string filePath, string text = null, bool isTTS = false) + { + string filename = Path.GetFileName(filePath); + using (var file = File.OpenRead(filePath)) + { + var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS }; + var model = await Discord.BaseClient.UploadFile(Id, file, args).ConfigureAwait(false); + return new Message(this, model); + } + } + /// + public async Task SendFile(Stream stream, string filename, string text = null, bool isTTS = false) + { + var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS }; + var model = await Discord.BaseClient.UploadFile(Id, stream, args).ConfigureAwait(false); + return new Message(this, model); + } + + /// + public async Task DeleteMessages(IEnumerable messages) + { + await Discord.BaseClient.DeleteMessages(Id, new DeleteMessagesParam { MessageIds = messages.Select(x => x.Id) }).ConfigureAwait(false); + } + + /// + public async Task TriggerTyping() + { + await Discord.BaseClient.TriggerTypingIndicator(Id).ConfigureAwait(false); + } + + /// + public async Task Close() + { + await Discord.BaseClient.DeleteChannel(Id).ConfigureAwait(false); + } + + /// + public async Task Update() + { + var model = await Discord.BaseClient.GetChannel(Id).ConfigureAwait(false); + Update(model); + } + + /// + public override string ToString() => $"@{Recipient} [DM]"; + + IDMUser IDMChannel.Recipient => Recipient; + + Task> IChannel.GetUsers() + => Task.FromResult(GetUsers()); + Task IChannel.GetUser(ulong id) + => Task.FromResult(GetUser(id)); + Task IMessageChannel.GetMessage(ulong id) + => throw new NotSupportedException(); + async Task> IMessageChannel.GetMessages(int limit) + => await GetMessages(limit).ConfigureAwait(false); + async Task> IMessageChannel.GetMessages(ulong fromMessageId, Direction dir, int limit) + => await GetMessages(fromMessageId, dir, limit).ConfigureAwait(false); + async Task IMessageChannel.SendMessage(string text, bool isTTS) + => await SendMessage(text, isTTS).ConfigureAwait(false); + async Task IMessageChannel.SendFile(string filePath, string text, bool isTTS) + => await SendFile(filePath, text, isTTS).ConfigureAwait(false); + async Task IMessageChannel.SendFile(Stream stream, string filename, string text, bool isTTS) + => await SendFile(stream, filename, text, isTTS).ConfigureAwait(false); + async Task IMessageChannel.TriggerTyping() + => await TriggerTyping().ConfigureAwait(false); + } +} diff --git a/src/Discord.Net/Entities/Rest/Channels/GuildChannel.cs b/src/Discord.Net/Entities/Rest/Channels/GuildChannel.cs new file mode 100644 index 000000000..746fb62b3 --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Channels/GuildChannel.cs @@ -0,0 +1,173 @@ +using Discord.API.Rest; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.Channel; + +namespace Discord.Rest +{ + public abstract class GuildChannel : IGuildChannel + { + private ConcurrentDictionary _overwrites; + + /// + public ulong Id { get; } + /// Gets the guild this channel is a member of. + public Guild Guild { get; } + + /// + public string Name { get; private set; } + /// + public int Position { get; private set; } + + /// + public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); + /// + public IReadOnlyDictionary PermissionOverwrites => _overwrites; + internal DiscordRestClient Discord => Guild.Discord; + + internal GuildChannel(Guild guild, Model model) + { + Id = model.Id; + Guild = guild; + + Update(model); + } + internal virtual void Update(Model model) + { + Name = model.Name; + Position = model.Position; + + var newOverwrites = new ConcurrentDictionary(); + for (int i = 0; i < model.PermissionOverwrites.Length; i++) + { + var overwrite = model.PermissionOverwrites[i]; + newOverwrites[overwrite.TargetId] = new Overwrite(overwrite); + } + _overwrites = newOverwrites; + } + + public async Task Modify(Action func) + { + if (func != null) throw new NullReferenceException(nameof(func)); + + var args = new ModifyGuildChannelParams(); + func(args); + var model = await Discord.BaseClient.ModifyGuildChannel(Id, args).ConfigureAwait(false); + Update(model); + } + + /// Gets a user in this channel with the given id. + public async Task GetUser(ulong id) + { + var model = await Discord.BaseClient.GetGuildMember(Guild.Id, id).ConfigureAwait(false); + if (model != null) + return new GuildUser(Guild, model); + return null; + } + protected abstract Task> GetUsers(); + + /// Gets the permission overwrite for a specific user, or null if one does not exist. + public OverwritePermissions? GetPermissionOverwrite(IUser user) + { + Overwrite value; + if (_overwrites.TryGetValue(Id, out value)) + return value.Permissions; + return null; + } + /// Gets the permission overwrite for a specific role, or null if one does not exist. + public OverwritePermissions? GetPermissionOverwrite(IRole role) + { + Overwrite value; + if (_overwrites.TryGetValue(Id, out value)) + return value.Permissions; + return null; + } + /// Downloads a collection of all invites to this channel. + public async Task> GetInvites() + { + var models = await Discord.BaseClient.GetChannelInvites(Id).ConfigureAwait(false); + return models.Select(x => new GuildInvite(Guild, x)); + } + + /// Adds or updates the permission overwrite for the given user. + public async Task AddPermissionOverwrite(IUser user, OverwritePermissions perms) + { + var args = new ModifyChannelPermissionsParams { Allow = perms.AllowValue, Deny = perms.DenyValue }; + await Discord.BaseClient.ModifyChannelPermissions(Id, user.Id, args).ConfigureAwait(false); + _overwrites[user.Id] = new Overwrite(new API.Overwrite { Allow = perms.AllowValue, Deny = perms.DenyValue, TargetId = user.Id, TargetType = PermissionTarget.User }); + } + /// Adds or updates the permission overwrite for the given role. + public async Task AddPermissionOverwrite(IRole role, OverwritePermissions perms) + { + var args = new ModifyChannelPermissionsParams { Allow = perms.AllowValue, Deny = perms.DenyValue }; + await Discord.BaseClient.ModifyChannelPermissions(Id, role.Id, args).ConfigureAwait(false); + _overwrites[role.Id] = new Overwrite(new API.Overwrite { Allow = perms.AllowValue, Deny = perms.DenyValue, TargetId = role.Id, TargetType = PermissionTarget.Role }); + } + /// Removes the permission overwrite for the given user, if one exists. + public async Task RemovePermissionOverwrite(IUser user) + { + await Discord.BaseClient.DeleteChannelPermission(Id, user.Id).ConfigureAwait(false); + + Overwrite value; + _overwrites.TryRemove(user.Id, out value); + } + /// Removes the permission overwrite for the given role, if one exists. + public async Task RemovePermissionOverwrite(IRole role) + { + await Discord.BaseClient.DeleteChannelPermission(Id, role.Id).ConfigureAwait(false); + + Overwrite value; + _overwrites.TryRemove(role.Id, out value); + } + + /// 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 isTemporary = false, bool withXkcd = false) + { + var args = new CreateChannelInviteParams + { + MaxAge = maxAge ?? 0, + MaxUses = maxUses ?? 0, + Temporary = isTemporary, + XkcdPass = withXkcd + }; + var model = await Discord.BaseClient.CreateChannelInvite(Id, args).ConfigureAwait(false); + return new GuildInvite(Guild, model); + } + + /// + public async Task Delete() + { + await Discord.BaseClient.DeleteChannel(Id).ConfigureAwait(false); + } + /// + public async Task Update() + { + var model = await Discord.BaseClient.GetChannel(Id).ConfigureAwait(false); + Update(model); + } + + /// + public override string ToString() => Name ?? Id.ToString(); + + IGuild IGuildChannel.Guild => Guild; + async Task IGuildChannel.CreateInvite(int? maxAge, int? maxUses, bool isTemporary, bool withXkcd) + => await CreateInvite(maxAge, maxUses, isTemporary, withXkcd).ConfigureAwait(false); + async Task> IGuildChannel.GetInvites() + => await GetInvites().ConfigureAwait(false); + async Task> IGuildChannel.GetUsers() + => await GetUsers().ConfigureAwait(false); + async Task IGuildChannel.GetUser(ulong id) + => await GetUser(id).ConfigureAwait(false); + async Task> IChannel.GetUsers() + => await GetUsers().ConfigureAwait(false); + async Task IChannel.GetUser(ulong id) + => await GetUser(id).ConfigureAwait(false); + } +} diff --git a/src/Discord.Net/Entities/Rest/Channels/TextChannel.cs b/src/Discord.Net/Entities/Rest/Channels/TextChannel.cs new file mode 100644 index 000000000..24ce2d7e9 --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Channels/TextChannel.cs @@ -0,0 +1,119 @@ +using Discord.API.Rest; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.Channel; + +namespace Discord.Rest +{ + public class TextChannel : GuildChannel, ITextChannel + { + /// + public string Topic { get; private set; } + + /// + public string Mention => MentionHelper.Mention(this); + + internal TextChannel(Guild guild, Model model) + : base(guild, model) + { + } + + internal override void Update(Model model) + { + Topic = model.Topic; + base.Update(model); + } + + public async Task Modify(Action func) + { + if (func != null) throw new NullReferenceException(nameof(func)); + + var args = new ModifyTextChannelParams(); + func(args); + var model = await Discord.BaseClient.ModifyGuildChannel(Id, args).ConfigureAwait(false); + Update(model); + } + + protected override async Task> GetUsers() + { + var users = await Guild.GetUsers().ConfigureAwait(false); + return users.Where(x => PermissionUtilities.GetValue(PermissionHelper.Resolve(x, this), ChannelPermission.ReadMessages)); + } + + /// + public Task GetMessage(ulong id) { throw new NotSupportedException(); } //Not implemented + /// + public async Task> GetMessages(int limit = DiscordConfig.MaxMessagesPerBatch) + { + var args = new GetChannelMessagesParams { Limit = limit }; + var models = await Discord.BaseClient.GetChannelMessages(Id, args).ConfigureAwait(false); + return models.Select(x => new Message(this, x)); + } + /// + public async Task> GetMessages(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) + { + var args = new GetChannelMessagesParams { Limit = limit }; + var models = await Discord.BaseClient.GetChannelMessages(Id, args).ConfigureAwait(false); + return models.Select(x => new Message(this, x)); + } + + /// + public async Task SendMessage(string text, bool isTTS = false) + { + var args = new CreateMessageParams { Content = text, IsTTS = isTTS }; + var model = await Discord.BaseClient.CreateMessage(Id, args).ConfigureAwait(false); + return new Message(this, model); + } + /// + public async Task SendFile(string filePath, string text = null, bool isTTS = false) + { + string filename = Path.GetFileName(filePath); + using (var file = File.OpenRead(filePath)) + { + var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS }; + var model = await Discord.BaseClient.UploadFile(Id, file, args).ConfigureAwait(false); + return new Message(this, model); + } + } + /// + public async Task SendFile(Stream stream, string filename, string text = null, bool isTTS = false) + { + var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS }; + var model = await Discord.BaseClient.UploadFile(Id, stream, args).ConfigureAwait(false); + return new Message(this, model); + } + + /// + public async Task DeleteMessages(IEnumerable messages) + { + await Discord.BaseClient.DeleteMessages(Id, new DeleteMessagesParam { MessageIds = messages.Select(x => x.Id) }).ConfigureAwait(false); + } + + /// + public async Task TriggerTyping() + { + await Discord.BaseClient.TriggerTypingIndicator(Id).ConfigureAwait(false); + } + + /// + public override string ToString() => $"{base.ToString()} [Text]"; + + async Task IMessageChannel.GetMessage(ulong id) + => await GetMessage(id).ConfigureAwait(false); + async Task> IMessageChannel.GetMessages(int limit) + => await GetMessages(limit).ConfigureAwait(false); + async Task> IMessageChannel.GetMessages(ulong fromMessageId, Direction dir, int limit) + => await GetMessages(fromMessageId, dir, limit).ConfigureAwait(false); + async Task IMessageChannel.SendMessage(string text, bool isTTS) + => await SendMessage(text, isTTS).ConfigureAwait(false); + async Task IMessageChannel.SendFile(string filePath, string text, bool isTTS) + => await SendFile(filePath, text, isTTS).ConfigureAwait(false); + async Task IMessageChannel.SendFile(Stream stream, string filename, string text, bool isTTS) + => await SendFile(stream, filename, text, isTTS).ConfigureAwait(false); + async Task IMessageChannel.TriggerTyping() + => await TriggerTyping().ConfigureAwait(false); + } +} diff --git a/src/Discord.Net/Entities/Rest/Channels/VoiceChannel.cs b/src/Discord.Net/Entities/Rest/Channels/VoiceChannel.cs new file mode 100644 index 000000000..703b58c01 --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Channels/VoiceChannel.cs @@ -0,0 +1,45 @@ +using Discord.API.Rest; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.Channel; + +namespace Discord.Rest +{ + public class VoiceChannel : GuildChannel, IVoiceChannel + { + /// + public int Bitrate { get; private set; } + + internal VoiceChannel(Guild guild, Model model) + : base(guild, model) + { + } + internal override void Update(Model model) + { + base.Update(model); + Bitrate = model.Bitrate; + } + + /// + public async Task Modify(Action func) + { + if (func != null) throw new NullReferenceException(nameof(func)); + + var args = new ModifyVoiceChannelParams(); + func(args); + var model = await Discord.BaseClient.ModifyGuildChannel(Id, args).ConfigureAwait(false); + Update(model); + } + + protected override async Task> GetUsers() + { + var users = await Guild.GetUsers().ConfigureAwait(false); + return users.Where(x => PermissionUtilities.GetValue(PermissionHelper.Resolve(x, this), ChannelPermission.Connect)); + } + + /// + public override string ToString() => $"{base.ToString()} [Voice]"; + } +} diff --git a/src/Discord.Net/Entities/Rest/Guilds/Guild.cs b/src/Discord.Net/Entities/Rest/Guilds/Guild.cs new file mode 100644 index 000000000..182091f72 --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Guilds/Guild.cs @@ -0,0 +1,365 @@ +using Discord.API.Rest; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.Guild; +using EmbedModel = Discord.API.GuildEmbed; +using RoleModel = Discord.API.Role; + +namespace Discord.Rest +{ + /// Represents a Discord guild (called a server in the official client). + public class Guild : IGuild + { + private ConcurrentDictionary _roles; + private string _iconId, _splashId; + + /// + public ulong Id { get; } + internal DiscordRestClient Discord { get; } + + /// + public string Name { get; private set; } + /// + public int AFKTimeout { get; private set; } + /// + public bool IsEmbeddable { get; private set; } + /// + public int VerificationLevel { get; private set; } + + /// + public ulong? AFKChannelId { get; private set; } + /// + public ulong? EmbedChannelId { get; private set; } + /// + public ulong OwnerId { get; private set; } + /// + public string VoiceRegionId { get; private set; } + /// + public IReadOnlyList Emojis { get; private set; } + /// + public IReadOnlyList Features { get; private set; } + + /// + public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); + /// + public string IconUrl => API.CDN.GetGuildIconUrl(Id, _iconId); + /// + public string SplashUrl => API.CDN.GetGuildSplashUrl(Id, _splashId); + /// + public ulong DefaultChannelId => Id; + /// + public Role EveryoneRole => GetRole(Id); + /// Gets a collection of all roles in this guild. + public IEnumerable Roles => _roles?.Select(x => x.Value) ?? Enumerable.Empty(); + + internal Guild(DiscordRestClient discord, Model model) + { + Id = model.Id; + Discord = discord; + + Update(model); + } + private void Update(Model model) + { + AFKChannelId = model.AFKChannelId; + AFKTimeout = model.AFKTimeout; + EmbedChannelId = model.EmbedChannelId; + IsEmbeddable = model.EmbedEnabled; + Features = model.Features; + _iconId = model.Icon; + Name = model.Name; + OwnerId = model.OwnerId; + VoiceRegionId = model.Region; + _splashId = model.Splash; + VerificationLevel = model.VerificationLevel; + + if (model.Emojis != null) + { + var emojis = ImmutableArray.CreateBuilder(model.Emojis.Length); + for (int i = 0; i < model.Emojis.Length; i++) + emojis[i] = new Emoji(model.Emojis[i]); + Emojis = emojis.ToArray(); + } + else + Emojis = ImmutableArray.Empty; + + var roles = new ConcurrentDictionary(1, model.Roles?.Length ?? 0); + if (model.Roles != null) + { + for (int i = 0; i < model.Roles.Length; i++) + roles[model.Roles[i].Id] = new Role(this, model.Roles[i]); + } + _roles = roles; + } + private void Update(EmbedModel model) + { + IsEmbeddable = model.Enabled; + EmbedChannelId = model.ChannelId; + } + private void Update(IEnumerable models) + { + Role role; + foreach (var model in models) + { + if (_roles.TryGetValue(model.Id, out role)) + role.Update(model); + } + } + + /// + public async Task Update() + { + var response = await Discord.BaseClient.GetGuild(Id).ConfigureAwait(false); + Update(response); + } + /// + public async Task Modify(Action func) + { + if (func == null) throw new NullReferenceException(nameof(func)); + + var args = new ModifyGuildParams(); + func(args); + var model = await Discord.BaseClient.ModifyGuild(Id, args).ConfigureAwait(false); + Update(model); + } + /// + public async Task ModifyEmbed(Action func) + { + if (func == null) throw new NullReferenceException(nameof(func)); + + var args = new ModifyGuildEmbedParams(); + func(args); + var model = await Discord.BaseClient.ModifyGuildEmbed(Id, args).ConfigureAwait(false); + + Update(model); + } + /// + public async Task ModifyChannels(IEnumerable args) + { + if (args == null) throw new NullReferenceException(nameof(args)); + + await Discord.BaseClient.ModifyGuildChannels(Id, args).ConfigureAwait(false); + } + /// + public async Task ModifyRoles(IEnumerable args) + { + if (args == null) throw new NullReferenceException(nameof(args)); + + var models = await Discord.BaseClient.ModifyGuildRoles(Id, args).ConfigureAwait(false); + Update(models); + } + /// + public async Task Leave() + { + await Discord.BaseClient.LeaveGuild(Id).ConfigureAwait(false); + } + /// + public async Task Delete() + { + await Discord.BaseClient.DeleteGuild(Id).ConfigureAwait(false); + } + + /// + public async Task> GetBans() + { + var models = await Discord.BaseClient.GetGuildBans(Id).ConfigureAwait(false); + return models.Select(x => new PublicUser(Discord, x)); + } + /// + public Task AddBan(IUser user, int pruneDays = 0) => AddBan(user, pruneDays); + /// + public async Task AddBan(ulong userId, int pruneDays = 0) + { + var args = new CreateGuildBanParams() + { + PruneDays = pruneDays + }; + await Discord.BaseClient.CreateGuildBan(Id, userId, args).ConfigureAwait(false); + } + /// + public Task RemoveBan(IUser user) => RemoveBan(user.Id); + /// + public async Task RemoveBan(ulong userId) + { + await Discord.BaseClient.RemoveGuildBan(Id, userId).ConfigureAwait(false); + } + + /// Gets the channel in this guild with the provided id, or null if not found. + public async Task GetChannel(ulong id) + { + var model = await Discord.BaseClient.GetChannel(Id, id).ConfigureAwait(false); + if (model != null) + return ToChannel(model); + return null; + } + /// Gets a collection of all channels in this guild. + public async Task> GetChannels() + { + var models = await Discord.BaseClient.GetGuildChannels(Id).ConfigureAwait(false); + return models.Select(x => ToChannel(x)); + } + /// Creates a new text channel. + public async Task CreateTextChannel(string name) + { + if (name == null) throw new ArgumentNullException(nameof(name)); + + var args = new CreateGuildChannelParams() { Name = name, Type = ChannelType.Text }; + var model = await Discord.BaseClient.CreateGuildChannel(Id, args).ConfigureAwait(false); + return new TextChannel(this, model); + } + /// Creates a new voice channel. + public async Task CreateVoiceChannel(string name) + { + if (name == null) throw new ArgumentNullException(nameof(name)); + + var args = new CreateGuildChannelParams { Name = name, Type = ChannelType.Voice }; + var model = await Discord.BaseClient.CreateGuildChannel(Id, args).ConfigureAwait(false); + return new VoiceChannel(this, model); + } + + /// Gets a collection of all integrations attached to this guild. + public async Task> GetIntegrations() + { + var models = await Discord.BaseClient.GetGuildIntegrations(Id).ConfigureAwait(false); + return models.Select(x => new GuildIntegration(this, x)); + } + /// Creates a new integration for this guild. + public async Task CreateIntegration(ulong id, string type) + { + var args = new CreateGuildIntegrationParams { Id = id, Type = type }; + var model = await Discord.BaseClient.CreateGuildIntegration(Id, args).ConfigureAwait(false); + return new GuildIntegration(this, model); + } + + /// Gets a collection of all invites to this guild. + public async Task> GetInvites() + { + var models = await Discord.BaseClient.GetGuildInvites(Id).ConfigureAwait(false); + return models.Select(x => new GuildInvite(this, x)); + } + /// Creates a new invite to this guild. + public async Task CreateInvite(int? maxAge = 1800, int? maxUses = null, bool isTemporary = false, bool withXkcd = false) + { + if (maxAge <= 0) throw new ArgumentOutOfRangeException(nameof(maxAge)); + if (maxUses <= 0) throw new ArgumentOutOfRangeException(nameof(maxUses)); + + var args = new CreateChannelInviteParams() + { + MaxAge = maxAge ?? 0, + MaxUses = maxUses ?? 0, + Temporary = isTemporary, + XkcdPass = withXkcd + }; + var model = await Discord.BaseClient.CreateChannelInvite(DefaultChannelId, args).ConfigureAwait(false); + return new GuildInvite(this, model); + } + + /// Gets the role in this guild with the provided id, or null if not found. + public Role GetRole(ulong id) + { + Role result = null; + if (_roles?.TryGetValue(id, out result) == true) + return result; + return null; + } + + /// Creates a new role. + public async Task CreateRole(string name, GuildPermissions? permissions = null, Color? color = null, bool isHoisted = false) + { + if (name == null) throw new ArgumentNullException(nameof(name)); + + var model = await Discord.BaseClient.CreateGuildRole(Id).ConfigureAwait(false); + var role = new Role(this, model); + + await role.Modify(x => + { + x.Name = name; + x.Permissions = (permissions ?? role.Permissions).RawValue; + x.Color = (color ?? Color.Default).RawValue; + x.Hoist = isHoisted; + }).ConfigureAwait(false); + + return role; + } + + /// Gets a collection of all users in this guild. + public async Task> GetUsers() + { + var args = new GetGuildMembersParams(); + var models = await Discord.BaseClient.GetGuildMembers(Id, args).ConfigureAwait(false); + return models.Select(x => new GuildUser(this, x)); + } + /// Gets a paged collection of all users in this guild. + public async Task> GetUsers(int limit, int offset) + { + var args = new GetGuildMembersParams { Limit = limit, Offset = offset }; + var models = await Discord.BaseClient.GetGuildMembers(Id, args).ConfigureAwait(false); + return models.Select(x => new GuildUser(this, x)); + } + + /// Gets the user in this guild with the provided id, or null if not found. + public async Task GetUser(ulong id) + { + var model = await Discord.BaseClient.GetGuildMember(Id, id).ConfigureAwait(false); + if (model != null) + return new GuildUser(this, model); + return null; + } + + public async Task PruneUsers(int days = 30, bool simulate = false) + { + var args = new GuildPruneParams() { Days = days }; + GetGuildPruneCountResponse model; + if (simulate) + model = await Discord.BaseClient.GetGuildPruneCount(Id, args).ConfigureAwait(false); + else + model = await Discord.BaseClient.BeginGuildPrune(Id, args).ConfigureAwait(false); + return model.Pruned; + } + + internal GuildChannel ToChannel(API.Channel model) + { + switch (model.Type) + { + case ChannelType.Text: + default: + return new TextChannel(this, model); + case ChannelType.Voice: + return new VoiceChannel(this, model); + } + } + + IEnumerable IGuild.Emojis => Emojis; + ulong IGuild.EveryoneRoleId => EveryoneRole.Id; + IEnumerable IGuild.Features => Features; + + async Task> IGuild.GetBans() + => await GetBans().ConfigureAwait(false); + async Task IGuild.GetChannel(ulong id) + => await GetChannel(id).ConfigureAwait(false); + async Task> IGuild.GetChannels() + => await GetChannels().ConfigureAwait(false); + async Task IGuild.CreateInvite(int? maxAge, int? maxUses, bool isTemporary, bool withXkcd) + => await CreateInvite(maxAge, maxUses, isTemporary, withXkcd).ConfigureAwait(false); + async Task IGuild.CreateRole(string name, GuildPermissions? permissions, Color? color, bool isHoisted) + => await CreateRole(name, permissions, color, isHoisted).ConfigureAwait(false); + async Task IGuild.CreateTextChannel(string name) + => await CreateTextChannel(name).ConfigureAwait(false); + async Task IGuild.CreateVoiceChannel(string name) + => await CreateVoiceChannel(name).ConfigureAwait(false); + async Task> IGuild.GetInvites() + => await GetInvites().ConfigureAwait(false); + Task IGuild.GetRole(ulong id) + => Task.FromResult(GetRole(id)); + Task> IGuild.GetRoles() + => Task.FromResult>(Roles); + async Task IGuild.GetUser(ulong id) + => await GetUser(id).ConfigureAwait(false); + async Task> IGuild.GetUsers() + => await GetUsers().ConfigureAwait(false); + } +} diff --git a/src/Discord.Net/Entities/Rest/Guilds/GuildEmbed.cs b/src/Discord.Net/Entities/Rest/Guilds/GuildEmbed.cs new file mode 100644 index 000000000..f455e4f6a --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Guilds/GuildEmbed.cs @@ -0,0 +1,32 @@ +using System; +using Model = Discord.API.GuildEmbed; + +namespace Discord.Rest +{ + public class GuildEmbed : IGuildEmbed + { + /// + public ulong Id { get; } + /// + public bool IsEnabled { get; private set; } + /// + public ulong? ChannelId { get; private set; } + + internal DiscordRestClient Discord { get; } + + /// + public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); + + internal GuildEmbed(DiscordRestClient discord, Model model) + { + Discord = discord; + Update(model); + } + + private void Update(Model model) + { + ChannelId = model.ChannelId; + IsEnabled = model.Enabled; + } + } +} diff --git a/src/Discord.Net/Entities/Rest/Guilds/GuildIntegration.cs b/src/Discord.Net/Entities/Rest/Guilds/GuildIntegration.cs new file mode 100644 index 000000000..8de8d09c9 --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Guilds/GuildIntegration.cs @@ -0,0 +1,85 @@ +using Discord.API.Rest; +using System; +using System.Threading.Tasks; +using Model = Discord.API.Integration; + +namespace Discord.Rest +{ + public class GuildIntegration : IGuildIntegration + { + /// + public ulong Id { get; private set; } + /// + public string Name { get; private set; } + /// + public string Type { get; private set; } + /// + public bool IsEnabled { get; private set; } + /// + public bool IsSyncing { get; private set; } + /// + public ulong ExpireBehavior { get; private set; } + /// + public ulong ExpireGracePeriod { get; private set; } + /// + public DateTime SyncedAt { get; private set; } + + /// + public Guild Guild { get; private set; } + /// + public Role Role { get; private set; } + /// + public User User { get; private set; } + /// + public IntegrationAccount Account { get; private set; } + internal DiscordRestClient Discord => Guild.Discord; + + internal GuildIntegration(Guild guild, Model model) + { + Guild = guild; + Update(model); + } + + private void Update(Model model) + { + Id = model.Id; + Name = model.Name; + Type = model.Type; + IsEnabled = model.Enabled; + IsSyncing = model.Syncing; + ExpireBehavior = model.ExpireBehavior; + ExpireGracePeriod = model.ExpireGracePeriod; + SyncedAt = model.SyncedAt; + + Role = Guild.GetRole(model.RoleId); + User = new PublicUser(Discord, model.User); + } + + /// + public async Task Delete() + { + await Discord.BaseClient.DeleteGuildIntegration(Guild.Id, Id).ConfigureAwait(false); + } + /// + public async Task Modify(Action func) + { + if (func == null) throw new NullReferenceException(nameof(func)); + + var args = new ModifyGuildIntegrationParams(); + func(args); + var model = await Discord.BaseClient.ModifyGuildIntegration(Guild.Id, Id, args).ConfigureAwait(false); + + Update(model); + } + /// + public async Task Sync() + { + await Discord.BaseClient.SyncGuildIntegration(Guild.Id, Id).ConfigureAwait(false); + } + + IGuild IGuildIntegration.Guild => Guild; + IRole IGuildIntegration.Role => Role; + IUser IGuildIntegration.User => User; + IIntegrationAccount IGuildIntegration.Account => Account; + } +} diff --git a/src/Discord.Net/Entities/Rest/Guilds/IntegrationAccount.cs b/src/Discord.Net/Entities/Rest/Guilds/IntegrationAccount.cs new file mode 100644 index 000000000..ba5fb431f --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Guilds/IntegrationAccount.cs @@ -0,0 +1,11 @@ +namespace Discord.Rest +{ + public class IntegrationAccount : IIntegrationAccount + { + /// + public string Id { get; } + + /// + public string Name { get; private set; } + } +} diff --git a/src/Discord.Net/Entities/Rest/Guilds/UserGUild.cs b/src/Discord.Net/Entities/Rest/Guilds/UserGUild.cs new file mode 100644 index 000000000..a5c30afcf --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Guilds/UserGUild.cs @@ -0,0 +1,55 @@ +using System; +using System.Threading.Tasks; +using Model = Discord.API.UserGuild; + +namespace Discord.Rest +{ + public class UserGuild : IUserGuild + { + private string _iconId; + + /// + public ulong Id { get; } + internal DiscordRestClient Discord { get; } + + /// + public string Name { get; private set; } + public bool IsOwner { get; private set; } + public GuildPermissions Permissions { get; private set; } + + /// + public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); + /// + public string IconUrl => API.CDN.GetGuildIconUrl(Id, _iconId); + + internal UserGuild(DiscordRestClient discord, Model model) + { + Discord = discord; + Id = model.Id; + + Update(model); + } + private void Update(Model model) + { + _iconId = model.Icon; + IsOwner = model.Owner; + Name = model.Name; + Permissions = new GuildPermissions(model.Permissions); + } + + /// + public async Task Leave() + { + if (IsOwner) + throw new InvalidOperationException("Unable to leave a guild the current user owns, use Delete() instead."); + await Discord.BaseClient.LeaveGuild(Id).ConfigureAwait(false); + } + /// + public async Task Delete() + { + if (!IsOwner) + throw new InvalidOperationException("Unable to leave a guild the current user owns, use Delete() instead."); + await Discord.BaseClient.DeleteGuild(Id).ConfigureAwait(false); + } + } +} diff --git a/src/Discord.Net/Entities/Rest/Guilds/VoiceRegion.cs b/src/Discord.Net/Entities/Rest/Guilds/VoiceRegion.cs new file mode 100644 index 000000000..557fca63d --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Guilds/VoiceRegion.cs @@ -0,0 +1,30 @@ +using Model = Discord.API.VoiceRegion; + +namespace Discord.Rest +{ + public class VoiceRegion : IVoiceRegion + { + /// + public string Id { get; } + /// + public string Name { get; } + /// + public bool IsVip { get; } + /// + public bool IsOptimal { get; } + /// + public string SampleHostname { get; } + /// + public int SamplePort { get; } + + internal VoiceRegion(Model model) + { + Id = model.Id; + Name = model.Name; + IsVip = model.IsVip; + IsOptimal = model.IsOptimal; + SampleHostname = model.SampleHostname; + SamplePort = model.SamplePort; + } + } +} diff --git a/src/Discord.Net/Entities/Rest/Helper/PermissionHelper.cs b/src/Discord.Net/Entities/Rest/Helper/PermissionHelper.cs new file mode 100644 index 000000000..260c6f33d --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Helper/PermissionHelper.cs @@ -0,0 +1,64 @@ +namespace Discord.Rest +{ + public static class PermissionHelper + { + public static uint Resolve(IGuildUser user) + { + var roles = user.Roles; + uint newPermissions = 0; + for (int i = 0; i < roles.Count; i++) + newPermissions |= roles[i].Permissions.RawValue; + return newPermissions; + } + + public static uint Resolve(IGuildUser user, IGuildChannel channel) + { + uint resolvedPermissions = 0; + + uint mask = ChannelPermissions.All(channel).RawValue; + if (user.Id == user.Guild.OwnerId || PermissionUtilities.GetValue(resolvedPermissions, GuildPermission.Administrator)) + resolvedPermissions = mask; //Owners and administrators always have all permissions + else + { + //Start with this user's guild permissions + resolvedPermissions = Resolve(user); + var overwrites = channel.PermissionOverwrites; + + Overwrite entry; + var roles = user.Roles; + if (roles.Count > 0) + { + for (int i = 0; i < roles.Count; i++) + { + if (overwrites.TryGetValue(roles[i].Id, out entry)) + resolvedPermissions &= ~entry.Permissions.DenyValue; + } + for (int i = 0; i < roles.Count; i++) + { + if (overwrites.TryGetValue(roles[i].Id, out entry)) + resolvedPermissions |= entry.Permissions.AllowValue; + } + } + if (overwrites.TryGetValue(user.Id, out entry)) + resolvedPermissions = (resolvedPermissions & ~entry.Permissions.DenyValue) | entry.Permissions.AllowValue; + + switch (channel) + { + case TextChannel _: + if (!PermissionUtilities.GetValue(resolvedPermissions, ChannelPermission.ReadMessages)) + resolvedPermissions = 0; //No read permission on a text channel removes all other permissions + break; + case VoiceChannel _: + if (!PermissionUtilities.GetValue(resolvedPermissions, ChannelPermission.Connect)) + resolvedPermissions = 0; //No read permission on a text channel removes all other permissions + break; + default: + resolvedPermissions &= mask; //Ensure we didnt get any permissions this channel doesnt support (from guildPerms, for example) + break; + } + } + + return resolvedPermissions; + } + } +} diff --git a/src/Discord.Net/Entities/Rest/Invites/GuildInvite.cs b/src/Discord.Net/Entities/Rest/Invites/GuildInvite.cs new file mode 100644 index 000000000..59871da42 --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Invites/GuildInvite.cs @@ -0,0 +1,52 @@ +using System.Threading.Tasks; +using Model = Discord.API.InviteMetadata; + +namespace Discord.Rest +{ + public class GuildInvite : Invite, IGuildInvite + { + /// Gets the guild this invite is linked to. + public Guild Guild { get; private set; } + /// + public ulong ChannelId { get; private set; } + + /// + public bool IsRevoked { get; private set; } + /// + public bool IsTemporary { get; private set; } + /// + public int? MaxAge { get; private set; } + /// + public int? MaxUses { get; private set; } + /// + public int Uses { get; private set; } + + internal override DiscordRestClient Discord => Guild.Discord; + + internal GuildInvite(Guild guild, Model model) + : base(model) + { + Guild = guild; + + Update(model); //Causes base.Update(Model) to be run twice, but that's fine. + } + private void Update(Model model) + { + base.Update(model); + IsRevoked = model.Revoked; + IsTemporary = model.Temporary; + MaxAge = model.MaxAge != 0 ? model.MaxAge : (int?)null; + MaxUses = model.MaxUses; + Uses = model.Uses; + } + + /// + public async Task Delete() + { + await Discord.BaseClient.DeleteInvite(Code).ConfigureAwait(false); + } + + IGuild IGuildInvite.Guild => Guild; + ulong IInvite.GuildId => Guild.Id; + } +} diff --git a/src/Discord.Net/Entities/Rest/Invites/Invite.cs b/src/Discord.Net/Entities/Rest/Invites/Invite.cs new file mode 100644 index 000000000..bba63dd9c --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Invites/Invite.cs @@ -0,0 +1,48 @@ +using System.Threading.Tasks; +using Model = Discord.API.Invite; + +namespace Discord.Rest +{ + public abstract class Invite : IInvite + { + protected ulong _guildId, _channelId; + + /// + public string Code { get; } + /// + public string XkcdCode { get; } + + /// + public string Url => $"{DiscordConfig.InviteUrl}/{XkcdCode ?? Code}"; + /// + public string XkcdUrl => XkcdCode != null ? $"{DiscordConfig.InviteUrl}/{XkcdCode}" : null; + + internal abstract DiscordRestClient Discord { get; } + + internal Invite(Model model) + { + Code = model.Code; + XkcdCode = model.XkcdPass; + + Update(model); + } + protected virtual void Update(Model model) + { + _guildId = model.Guild.Id; + _channelId = model.Channel.Id; + } + + /// + public async Task Accept() + { + await Discord.BaseClient.AcceptInvite(Code).ConfigureAwait(false); + } + + /// + public override string ToString() => XkcdUrl ?? Url; + + string IEntity.Id => Code; + ulong IInvite.GuildId => _guildId; + ulong IInvite.ChannelId => _channelId; + } +} diff --git a/src/Discord.Net/Entities/Rest/Invites/PublicInvite.cs b/src/Discord.Net/Entities/Rest/Invites/PublicInvite.cs new file mode 100644 index 000000000..052a146e6 --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Invites/PublicInvite.cs @@ -0,0 +1,39 @@ +using System.Threading.Tasks; +using Model = Discord.API.Invite; + +namespace Discord.Rest +{ + public class PublicInvite : Invite, IPublicInvite + { + /// + public string GuildName { get; private set; } + /// + public string ChannelName { get; private set; } + + /// + public ulong GuildId => _guildId; + /// + public ulong ChannelId => _channelId; + + internal override DiscordRestClient Discord { get; } + + internal PublicInvite(DiscordRestClient discord, Model model) + : base(model) + { + Discord = discord; + } + protected override void Update(Model model) + { + base.Update(model); + GuildName = model.Guild.Name; + ChannelName = model.Channel.Name; + } + + /// + public async Task Update() + { + var model = await Discord.BaseClient.GetInvite(Code).ConfigureAwait(false); + Update(model); + } + } +} diff --git a/src/Discord.Net/Entities/Rest/Message.cs b/src/Discord.Net/Entities/Rest/Message.cs new file mode 100644 index 000000000..9ad797de0 --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Message.cs @@ -0,0 +1,140 @@ +using Discord.API.Rest; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Model = Discord.API.Message; + +namespace Discord.Rest +{ + public class Message : IMessage + { + /// + public ulong Id { get; } + + /// + public DateTime? EditedTimestamp { get; private set; } + /// + public bool IsTTS { get; private set; } + /// + public string RawText { get; private set; } + /// + public string Text { get; private set; } + /// + public DateTime Timestamp { get; private set; } + + /// + public IMessageChannel Channel { get; } + /// + public User Author { get; } + + /// + public IReadOnlyList Attachments { get; private set; } + /// + public IReadOnlyList Embeds { get; private set; } + /// + public IReadOnlyList MentionedUsers { get; private set; } + /// + public IReadOnlyList MentionedChannelIds { get; private set; } + /// + public IReadOnlyList MentionedRoleIds { get; private set; } + + /// + public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); + /// + public bool IsAuthor => Discord.CurrentUser.Id == Author.Id; + internal DiscordRestClient Discord => (Channel as TextChannel)?.Discord ?? (Channel as DMChannel).Discord; + + internal Message(IMessageChannel channel, Model model) + { + Id = model.Id; + Channel = channel; + Author = new PublicUser(Discord, model.Author); + + Update(model); + } + private void Update(Model model) + { + IsTTS = model.IsTextToSpeech; + Timestamp = model.Timestamp; + EditedTimestamp = model.EditedTimestamp; + RawText = model.Content; + + if (model.Attachments.Length > 0) + { + 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); + } + else + Attachments = ImmutableArray.Empty; + + 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; + + if (model.Mentions.Length > 0) + { + var discord = Discord; + var builder = ImmutableArray.CreateBuilder(model.Mentions.Length); + for (int i = 0; i < model.Mentions.Length; i++) + builder[i] = new PublicUser(discord, model.Mentions[i]); + MentionedUsers = builder.ToArray(); + } + else + MentionedUsers = ImmutableArray.Empty; + MentionedChannelIds = MentionHelper.GetChannelMentions(model.Content); + MentionedRoleIds = MentionHelper.GetRoleMentions(model.Content); + if (model.IsMentioningEveryone) + { + ulong? guildId = (Channel as IGuildChannel)?.Guild.Id; + if (guildId != null) + { + if (MentionedRoleIds.Count == 0) + MentionedRoleIds = ImmutableArray.Create(guildId.Value); + else + { + var builder = ImmutableArray.CreateBuilder(MentionedRoleIds.Count + 1); + builder.AddRange(MentionedRoleIds); + builder.Add(guildId.Value); + MentionedRoleIds = builder.ToImmutable(); + } + } + } + + Text = MentionHelper.CleanUserMentions(model.Content, model.Mentions); + + Author.Update(model.Author); + } + + /// + public async Task Modify(Action func) + { + if (func == null) throw new NullReferenceException(nameof(func)); + + var args = new ModifyMessageParams(); + func(args); + var model = await Discord.BaseClient.ModifyMessage(Channel.Id, Id, args).ConfigureAwait(false); + Update(model); + } + + /// + public async Task Delete() + { + await Discord.BaseClient.DeleteMessage(Channel.Id, Id).ConfigureAwait(false); + } + + IUser IMessage.Author => Author; + IReadOnlyList IMessage.Attachments => Attachments; + IReadOnlyList IMessage.Embeds => Embeds; + IReadOnlyList IMessage.MentionedChannelIds => MentionedChannelIds; + IReadOnlyList IMessage.MentionedUsers => MentionedUsers; + } +} diff --git a/src/Discord.Net/Entities/Rest/Role.cs b/src/Discord.Net/Entities/Rest/Role.cs new file mode 100644 index 000000000..bca559225 --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Role.cs @@ -0,0 +1,80 @@ +using Discord.API.Rest; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Model = Discord.API.Role; + +namespace Discord.Rest +{ + public class Role : IRole, IMentionable + { + /// + public ulong Id { get; } + /// Returns the guild this role belongs to. + public Guild Guild { get; } + + /// + public Color Color { get; private set; } + /// + public bool IsHoisted { get; private set; } + /// + public bool IsManaged { get; private set; } + /// + public string Name { get; private set; } + /// + public GuildPermissions Permissions { get; private set; } + /// + public int Position { get; private set; } + + /// + public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); + /// + public bool IsEveryone => Id == Guild.Id; + /// + public string Mention => MentionHelper.Mention(this); + internal DiscordRestClient Discord => Guild.Discord; + + internal Role(Guild guild, Model model) + { + Id = model.Id; + Guild = guild; + + Update(model); + } + internal void Update(Model model) + { + 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); + } + /// Modifies the properties of this role. + public async Task Modify(Action func) + { + if (func == null) throw new NullReferenceException(nameof(func)); + + var args = new ModifyGuildRoleParams(); + func(args); + var response = await Discord.BaseClient.ModifyGuildRole(Guild.Id, Id, args).ConfigureAwait(false); + Update(response); + } + /// Deletes this message. + public async Task Delete() + => await Discord.BaseClient.DeleteGuildRole(Guild.Id, Id).ConfigureAwait(false); + + /// + public override string ToString() => Name ?? Id.ToString(); + + ulong IRole.GuildId => Guild.Id; + + async Task> IRole.GetUsers() + { + //A tad hacky, but it works + var models = await Discord.BaseClient.GetGuildMembers(Guild.Id, new GetGuildMembersParams()).ConfigureAwait(false); + return models.Where(x => x.Roles.Contains(Id)).Select(x => new GuildUser(Guild, x)); + } + } +} diff --git a/src/Discord.Net/Entities/Rest/Users/Connection.cs b/src/Discord.Net/Entities/Rest/Users/Connection.cs new file mode 100644 index 000000000..6f243515a --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Users/Connection.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Model = Discord.API.Connection; + +namespace Discord.Rest +{ + public class Connection : IConnection + { + public string Id { get; } + + public string Type { get; private set; } + public string Name { get; private set; } + public bool IsRevoked { get; private set; } + + public IEnumerable Integrations { get; private set; } + + public Connection(Model model) + { + Id = model.Id; + + Type = model.Type; + Name = model.Name; + IsRevoked = model.Revoked; + + Integrations = model.Integrations; + } + } +} diff --git a/src/Discord.Net/Entities/Rest/Users/DMUser.cs b/src/Discord.Net/Entities/Rest/Users/DMUser.cs new file mode 100644 index 000000000..d613a0272 --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Users/DMUser.cs @@ -0,0 +1,20 @@ +using Model = Discord.API.User; + +namespace Discord.Rest +{ + public class DMUser : User, IDMUser + { + /// + public DMChannel Channel { get; } + + internal override DiscordRestClient Discord => Channel.Discord; + + internal DMUser(DMChannel channel, Model model) + : base(model) + { + Channel = channel; + } + + IDMChannel IDMUser.Channel => Channel; + } +} diff --git a/src/Discord.Net/Entities/Rest/Users/GuildUser.cs b/src/Discord.Net/Entities/Rest/Users/GuildUser.cs new file mode 100644 index 000000000..858a41295 --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Users/GuildUser.cs @@ -0,0 +1,97 @@ +using Discord.API.Rest; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Model = Discord.API.GuildMember; + +namespace Discord.Rest +{ + public class GuildUser : User, IGuildUser + { + private ImmutableArray _roles; + + public Guild Guild { get; } + + /// + public bool IsDeaf { get; private set; } + /// + public bool IsMute { get; private set; } + /// + public DateTime JoinedAt { get; private set; } + /// + public string Nickname { get; private set; } + + /// + public IReadOnlyList Roles => _roles; + internal override DiscordRestClient Discord => Guild.Discord; + + internal GuildUser(Guild guild, Model model) + : base(model.User) + { + Guild = guild; + } + internal void Update(Model model) + { + IsDeaf = model.Deaf; + IsMute = model.Mute; + JoinedAt = model.JoinedAt.Value; + Nickname = model.Nick; + + var roles = ImmutableArray.CreateBuilder(model.Roles.Length + 1); + roles[0] = Guild.EveryoneRole; + for (int i = 0; i < model.Roles.Length; i++) + roles[i + 1] = Guild.GetRole(model.Roles[i]); + _roles = roles.ToImmutable(); + } + + public async Task Update() + { + var model = await Discord.BaseClient.GetGuildMember(Guild.Id, Id).ConfigureAwait(false); + Update(model); + } + + public bool HasRole(IRole role) + { + for (int i = 0; i < _roles.Length; i++) + { + if (_roles[i].Id == role.Id) + return true; + } + return false; + } + + public async Task Kick() + { + await Discord.BaseClient.RemoveGuildMember(Guild.Id, Id).ConfigureAwait(false); + } + + public GuildPermissions GetGuildPermissions() + { + return new GuildPermissions(PermissionHelper.Resolve(this)); + } + public ChannelPermissions GetPermissions(IGuildChannel channel) + { + if (channel == null) throw new ArgumentNullException(nameof(channel)); + return new ChannelPermissions(PermissionHelper.Resolve(this, channel)); + } + + public async Task Modify(Action func) + { + if (func == null) throw new NullReferenceException(nameof(func)); + + var args = new ModifyGuildMemberParams(); + func(args); + var model = await Discord.BaseClient.ModifyGuildMember(Guild.Id, Id, args).ConfigureAwait(false); + Update(model); + } + + + IGuild IGuildUser.Guild => Guild; + IReadOnlyList IGuildUser.Roles => Roles; + ulong? IGuildUser.VoiceChannelId => null; + + ChannelPermissions IGuildUser.GetPermissions(IGuildChannel channel) + => GetPermissions(channel); + } +} diff --git a/src/Discord.Net/Entities/Rest/Users/PublicUser.cs b/src/Discord.Net/Entities/Rest/Users/PublicUser.cs new file mode 100644 index 000000000..1334115d8 --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Users/PublicUser.cs @@ -0,0 +1,15 @@ +using Model = Discord.API.User; + +namespace Discord.Rest +{ + public class PublicUser : User + { + internal override DiscordRestClient Discord { get; } + + internal PublicUser(DiscordRestClient discord, Model model) + : base(model) + { + Discord = discord; + } + } +} diff --git a/src/Discord.Net/Entities/Rest/Users/SelfUser.cs b/src/Discord.Net/Entities/Rest/Users/SelfUser.cs new file mode 100644 index 000000000..8bffc25f9 --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Users/SelfUser.cs @@ -0,0 +1,48 @@ +using Discord.API.Rest; +using System; +using System.Threading.Tasks; +using Model = Discord.API.User; + +namespace Discord.Rest +{ + public class SelfUser : User, ISelfUser + { + internal override DiscordRestClient Discord { get; } + + /// + public string Email { get; private set; } + /// + public bool IsVerified { get; private set; } + + internal SelfUser(DiscordRestClient discord, Model model) + : base(model) + { + Discord = discord; + } + internal override void Update(Model model) + { + base.Update(model); + + Email = model.Email; + IsVerified = model.IsVerified; + } + + /// + public async Task Update() + { + var model = await Discord.BaseClient.GetCurrentUser().ConfigureAwait(false); + Update(model); + } + + /// + public async Task Modify(Action func) + { + if (func != null) throw new NullReferenceException(nameof(func)); + + var args = new ModifyCurrentUserParams(); + func(args); + var model = await Discord.BaseClient.ModifyCurrentUser(args).ConfigureAwait(false); + Update(model); + } + } +} diff --git a/src/Discord.Net/Entities/Rest/Users/User.cs b/src/Discord.Net/Entities/Rest/Users/User.cs new file mode 100644 index 000000000..2f7800997 --- /dev/null +++ b/src/Discord.Net/Entities/Rest/Users/User.cs @@ -0,0 +1,66 @@ +using Discord.API.Rest; +using System; +using System.Threading.Tasks; +using Model = Discord.API.User; + +namespace Discord.Rest +{ + public abstract class User : IUser + { + private string _avatarId; + + /// + public ulong Id { get; } + internal abstract DiscordRestClient Discord { get; } + + /// + public ushort Discriminator { get; private set; } + /// + public bool IsBot { get; private set; } + /// + public string Username { get; private set; } + + /// + public string AvatarUrl => API.CDN.GetUserAvatarUrl(Id, _avatarId); + /// + public DateTime CreatedAt => DateTimeHelper.FromSnowflake(Id); + /// + public string Mention => MentionHelper.Mention(this, false); + /// + public string NicknameMention => MentionHelper.Mention(this, true); + + internal User(Model model) + { + Id = model.Id; + + Update(model); + } + internal virtual void Update(Model model) + { + _avatarId = model.Avatar; + Discriminator = model.Discriminator; + IsBot = model.Bot; + Username = model.Username; + } + + public async Task CreateDMChannel() + { + var args = new CreateDMChannelParams + { + RecipientId = Id + }; + var model = await Discord.BaseClient.CreateDMChannel(args).ConfigureAwait(false); + + return new DMChannel(Discord, model); + } + + /// + string IUser.CurrentGame => null; + /// + UserStatus IUser.Status => UserStatus.Unknown; + + /// + async Task IUser.CreateDMChannel() + => await CreateDMChannel().ConfigureAwait(false); + } +} diff --git a/src/Discord.Net/Entities/Role.cs b/src/Discord.Net/Entities/Role.cs deleted file mode 100644 index 1e138c911..000000000 --- a/src/Discord.Net/Entities/Role.cs +++ /dev/null @@ -1,85 +0,0 @@ -using Discord.API.Rest; -using Discord.Net; -using System; -using System.Collections.Generic; -using System.Net; -using System.Threading.Tasks; -using Model = Discord.API.Role; - -namespace Discord -{ - public class Role : IEntity, IMentionable - { - /// - public ulong Id { get; } - /// Returns the guild this role belongs to. - public Guild Guild { get; } - - /// Gets the name of this role. - public string Name { get; private set; } - /// 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; } - /// Returns true if this role is managed by the Discord server (e.g. for Twitch integration) - public bool IsManaged { get; private set; } - /// 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; } - - /// - 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, Guild guild) - { - Id = id; - Guild = guild; - } - - internal void Update(Model model) - { - 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); - } - - /// - public Task Update() { throw new NotSupportedException(); } //TODO: Not supported yet - - /// Modifies the properties of this role. - public async Task Modify(Action func) - { - if (func != null) throw new NullReferenceException(nameof(func)); - - 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 Discord.RestClient.Send(new DeleteGuildRoleRequest(Guild.Id, Id)).ConfigureAwait(false); } - catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } - } - - internal void UpdatePermissions() - { - foreach (var member in Members) - Guild.UpdatePermissions(member); - } - - /// - public override string ToString() => $"{Guild}/{Name ?? Id.ToString()}"; - } -} diff --git a/src/Discord.Net/Entities/Users/DMUser.cs b/src/Discord.Net/Entities/Users/DMUser.cs deleted file mode 100644 index 982f8aea5..000000000 --- a/src/Discord.Net/Entities/Users/DMUser.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Threading.Tasks; -using Model = Discord.API.User; - -namespace Discord -{ - public class DMUser : IUser - { - private readonly GlobalUser _user; - - public DMChannel Channel { get; } - - /// - public DiscordClient Discord => _user.Discord; - /// - public ulong Id => _user.Id; - /// - public string Username => _user.Username; - /// - public ushort Discriminator => _user.Discriminator; - /// - public bool IsBot => _user.IsBot; - /// - public string CurrentGame => _user.CurrentGame; - /// - public UserStatus Status => _user.Status; - /// - public string AvatarUrl => _user.AvatarUrl; - /// - public string Mention => _user.Mention; - - internal DMUser(GlobalUser user, DMChannel channel) - { - _user = user; - Channel = channel; - } - - public void Update(Model model) => _user.Update(model); - - public virtual Task Update() { throw new NotSupportedException(); } - } -} diff --git a/src/Discord.Net/Entities/Users/GlobalUser.cs b/src/Discord.Net/Entities/Users/GlobalUser.cs deleted file mode 100644 index 2bb72b18a..000000000 --- a/src/Discord.Net/Entities/Users/GlobalUser.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Threading.Tasks; -using Model = Discord.API.User; - -namespace Discord -{ - public class GlobalUser : IUser, IEntity - { - private string _avatarId; - private int _refCount; - - /// - public ulong Id { get; } - /// - public DiscordClient Discord { get; } - - public string Username { get; private set; } - public ushort Discriminator { get; private set; } - public bool IsBot { get; private set; } - public string CurrentGame { get; private set; } - public UserStatus Status { get; private set; } - - public string AvatarUrl => CDN.GetUserAvatarUrl(Id, _avatarId); - public string Mention => MentionHelper.Mention(this); - - internal GlobalUser(ulong id, DiscordClient discord) - { - Id = id; - Discord = discord; - } - 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); - - internal void Attach(IUser user) - { - //Only ever called from the gateway thread - _refCount++; - } - internal void Detach(IUser user) - { - //Only ever called from the gateway thread - if (--_refCount == 0) - Discord.RemoveUser(this); - } - } -} diff --git a/src/Discord.Net/Entities/Users/GuildUser.cs b/src/Discord.Net/Entities/Users/GuildUser.cs deleted file mode 100644 index ba2e4198a..000000000 --- a/src/Discord.Net/Entities/Users/GuildUser.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Discord.API.Rest; -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Threading.Tasks; -using Model = Discord.API.GuildMember; - -namespace Discord -{ - public class GuildUser : IUser - { - private readonly GlobalUser _user; - - public Guild Guild { get; } - - /// - public string CurrentGame { get; private set; } - /// - public UserStatus Status { get; private set; } - public VoiceChannel VoiceChannel { get; private set; } - - /// - public DiscordClient Discord => _user.Discord; - /// - public ulong Id => _user.Id; - /// - public string Username => _user.Username; - /// - public ushort Discriminator => _user.Discriminator; - /// - public bool IsBot => _user.IsBot; - /// - public string AvatarUrl => _user.AvatarUrl; - /// - public string Mention => _user.Mention; - - /// - public IReadOnlyList Roles { get; private set; } - - internal GuildUser(GlobalUser user, Guild guild) - { - _user = user; - Guild = guild; - } - internal void Update(Model model) - { - JoinedAt = model.JoinedAt.Value; - Roles = model.Roles.Select(x => Guild.GetRole(x)).ToImmutableArray(); - } - - public bool HasRole(Role role) => false; //TODO: Implement - - 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)); - - /// - public DateTime JoinedAt { get; private set; } - public GuildPermissions GuildPermissions { get; internal set; } - public Task CreateDMChannel() => _user.CreateDMChannel(); - - /// - public Task Update() { throw new NotSupportedException(); } //TODO: Not supported - - public ChannelPermissions GetPermissions(GuildChannel channel) - { - if (channel == null) throw new ArgumentNullException(nameof(channel)); - return channel.GetPermissions(this); - } - - public async Task Modify(Action func) - { - if (func != null) throw new NullReferenceException(nameof(func)); - - var req = new ModifyGuildMemberRequest(Guild.Id, Id); - func(req); - await Discord.RestClient.Send(req).ConfigureAwait(false); - } - } -} diff --git a/src/Discord.Net/Entities/Users/IUser.cs b/src/Discord.Net/Entities/Users/IUser.cs deleted file mode 100644 index 0e6071224..000000000 --- a/src/Discord.Net/Entities/Users/IUser.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Discord -{ - public interface IUser : IEntity - { - string Username { get; } - ushort Discriminator { get; } - bool IsBot { get; } - - string AvatarUrl { get; } - string Mention { get; } - string CurrentGame { get; } - UserStatus Status { get; } - } -} diff --git a/src/Discord.Net/Entities/Users/SelfUser.cs b/src/Discord.Net/Entities/Users/SelfUser.cs deleted file mode 100644 index 8d5bbbafa..000000000 --- a/src/Discord.Net/Entities/Users/SelfUser.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Model = Discord.API.User; - -namespace Discord -{ - public class SelfUser : GlobalUser - { - public string Email { get; private set; } - public bool IsVerified { get; private set; } - - internal SelfUser(ulong id, DiscordClient discord) - : base(id, discord) - { - } - - internal override void Update(Model model) - { - base.Update(model); - - Email = model.Email; - IsVerified = model.IsVerified; - } - } -} diff --git a/src/Discord.Net/Entities/VoiceRegion.cs b/src/Discord.Net/Entities/VoiceRegion.cs deleted file mode 100644 index bba703240..000000000 --- a/src/Discord.Net/Entities/VoiceRegion.cs +++ /dev/null @@ -1,60 +0,0 @@ -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/Enums/ConnectionState.cs b/src/Discord.Net/Enums/ConnectionState.cs deleted file mode 100644 index dfd4ac9eb..000000000 --- a/src/Discord.Net/Enums/ConnectionState.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Discord -{ - public enum ConnectionState - { - Disconnected, - Connecting, - Connected, - Disconnecting - } -} diff --git a/src/Discord.Net/Events/ChannelEventArgs.cs b/src/Discord.Net/Events/ChannelEventArgs.cs deleted file mode 100644 index b03db540f..000000000 --- a/src/Discord.Net/Events/ChannelEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Discord -{ - public class ChannelEventArgs : EventArgs - { - public IChannel Channel { get; } - - public ChannelEventArgs(IChannel channel) - { - Channel = channel; - } - } -} diff --git a/src/Discord.Net/Events/ChannelUpdatedEventArgs.cs b/src/Discord.Net/Events/ChannelUpdatedEventArgs.cs deleted file mode 100644 index b4fbc258f..000000000 --- a/src/Discord.Net/Events/ChannelUpdatedEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Discord -{ - public class ChannelUpdatedEventArgs : ChannelEventArgs - { - public IChannel Before { get; } - public IChannel After => Channel; - - public ChannelUpdatedEventArgs(IChannel before, IChannel after) - : base(after) - { - Before = before; - } - } -} diff --git a/src/Discord.Net/Events/CurrentUserEventArgs.cs b/src/Discord.Net/Events/CurrentUserEventArgs.cs deleted file mode 100644 index a947bbfc5..000000000 --- a/src/Discord.Net/Events/CurrentUserEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index 4309f0312..000000000 --- a/src/Discord.Net/Events/CurrentUserUpdatedEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index cf7c1bf70..000000000 --- a/src/Discord.Net/Events/DisconnectedEventArgs.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace Discord -{ - public class DisconnectedEventArgs : EventArgs - { - public bool WasUnexpected { get; } - public Exception Exception { get; } - - public DisconnectedEventArgs(bool wasUnexpected, Exception exception = null) - { - WasUnexpected = wasUnexpected; - Exception = exception; - } - } -} diff --git a/src/Discord.Net/Events/GuildEventArgs.cs b/src/Discord.Net/Events/GuildEventArgs.cs deleted file mode 100644 index 50625d882..000000000 --- a/src/Discord.Net/Events/GuildEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index 9258072f7..000000000 --- a/src/Discord.Net/Events/GuildUpdatedEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -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 83de48616..dd8c885ee 100644 --- a/src/Discord.Net/Events/LogMessageEventArgs.cs +++ b/src/Discord.Net/Events/LogMessageEventArgs.cs @@ -34,7 +34,7 @@ namespace Discord builder.Clear(); builder.EnsureCapacity(maxLength); } - + if (sourceName != null) { builder.Append('['); diff --git a/src/Discord.Net/Events/MessageEventArgs.cs b/src/Discord.Net/Events/MessageEventArgs.cs deleted file mode 100644 index 366b16dbb..000000000 --- a/src/Discord.Net/Events/MessageEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Discord -{ - public class MessageEventArgs : EventArgs - { - public Message Message { get; } - - public MessageEventArgs(Message message) - { - Message = message; - } - } -} diff --git a/src/Discord.Net/Events/MessageUpdatedEventArgs.cs b/src/Discord.Net/Events/MessageUpdatedEventArgs.cs deleted file mode 100644 index 318ac9d54..000000000 --- a/src/Discord.Net/Events/MessageUpdatedEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Discord -{ - public class MessageUpdatedEventArgs : MessageEventArgs - { - public Message Before { get; } - public Message After => Message; - - public MessageUpdatedEventArgs(Message before, Message after) - : base(after) - { - Before = before; - } - } -} diff --git a/src/Discord.Net/Events/RoleEventArgs.cs b/src/Discord.Net/Events/RoleEventArgs.cs deleted file mode 100644 index 887972ffe..000000000 --- a/src/Discord.Net/Events/RoleEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Discord -{ - public class RoleEventArgs : EventArgs - { - public Role Role { get; } - - public RoleEventArgs(Role role) - { - Role = role; - } - } -} diff --git a/src/Discord.Net/Events/RoleUpdatedEventArgs.cs b/src/Discord.Net/Events/RoleUpdatedEventArgs.cs deleted file mode 100644 index 285ab42c5..000000000 --- a/src/Discord.Net/Events/RoleUpdatedEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Discord -{ - public class RoleUpdatedEventArgs : RoleEventArgs - { - public Role Before { get; } - public Role After => Role; - - public RoleUpdatedEventArgs(Role before, Role after) - : base(after) - { - Before = before; - } - } -} diff --git a/src/Discord.Net/Events/SentRequestEventArgs.cs b/src/Discord.Net/Events/SentRequestEventArgs.cs new file mode 100644 index 000000000..c62c4d917 --- /dev/null +++ b/src/Discord.Net/Events/SentRequestEventArgs.cs @@ -0,0 +1,20 @@ +using System; + +namespace Discord.Net.Rest +{ + public class SentRequestEventArgs : EventArgs + { + public string Method { get; } + public string Endpoint { get; } + public int ResponseLength { get; } + public double Milliseconds { get; } + + public SentRequestEventArgs(string method, string endpoint, int responseLength, double milliseconds) + { + Method = method; + Endpoint = endpoint; + ResponseLength = responseLength; + Milliseconds = milliseconds; + } + } +} diff --git a/src/Discord.Net/Events/TypingEventArgs.cs b/src/Discord.Net/Events/TypingEventArgs.cs deleted file mode 100644 index 02c803b1f..000000000 --- a/src/Discord.Net/Events/TypingEventArgs.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace Discord -{ - public class TypingEventArgs : EventArgs - { - public IMessageChannel Channel { get; } - public IUser User { get; } - - public TypingEventArgs(IMessageChannel channel, IUser user) - { - Channel = channel; - User = user; - } - } -} diff --git a/src/Discord.Net/Events/UserEventArgs.cs b/src/Discord.Net/Events/UserEventArgs.cs deleted file mode 100644 index a9139c2f8..000000000 --- a/src/Discord.Net/Events/UserEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Discord -{ - public class UserEventArgs : EventArgs - { - public IUser User { get; } - - public UserEventArgs(IUser user) - { - User = user; - } - } -} diff --git a/src/Discord.Net/Events/UserUpdatedEventArgs.cs b/src/Discord.Net/Events/UserUpdatedEventArgs.cs deleted file mode 100644 index e6c93fc47..000000000 --- a/src/Discord.Net/Events/UserUpdatedEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Discord -{ - public class UserUpdatedEventArgs : UserEventArgs - { - public IUser Before { get; } - public IUser After => User; - - public UserUpdatedEventArgs(IUser before, IUser after) - : base(after) - { - Before = before; - } - } -} diff --git a/src/Discord.Net/Events/VoiceChannelEventArgs.cs b/src/Discord.Net/Events/VoiceChannelEventArgs.cs deleted file mode 100644 index 78d519d2f..000000000 --- a/src/Discord.Net/Events/VoiceChannelEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index 1e8ae00b9..000000000 --- a/src/Discord.Net/Format.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System.Text; - -namespace Discord -{ - public static class Format - { - private static readonly string[] _patterns = new string[] { "__", "_", "**", "*", "~~", "```", "`" }; - private static readonly StringBuilder _builder = new StringBuilder(DiscordConfig.MaxMessageSize); - - /// 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('\\'); - } - - 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; - - 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; - } - } - } - 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}`"; - } - } -} diff --git a/src/Discord.Net/Helpers/DateTimeHelper.cs b/src/Discord.Net/Helpers/DateTimeHelper.cs new file mode 100644 index 000000000..a93efcb1d --- /dev/null +++ b/src/Discord.Net/Helpers/DateTimeHelper.cs @@ -0,0 +1,17 @@ +using System; + +namespace Discord +{ + internal static class DateTimeHelper + { + private const ulong EpochTicks = 621355968000000000UL; + + public static DateTime FromEpochMilliseconds(ulong value) + => new DateTime((long)(value * TimeSpan.TicksPerMillisecond + EpochTicks), DateTimeKind.Utc); + public static DateTime FromEpochSeconds(ulong value) + => new DateTime((long)(value * TimeSpan.TicksPerSecond + EpochTicks), DateTimeKind.Utc); + + public static DateTime FromSnowflake(ulong value) + => FromEpochMilliseconds((value >> 22) + 1420070400000UL); + } +} diff --git a/src/Discord.Net/Helpers/EventExtensions.cs b/src/Discord.Net/Helpers/EventExtensions.cs new file mode 100644 index 000000000..a024822b7 --- /dev/null +++ b/src/Discord.Net/Helpers/EventExtensions.cs @@ -0,0 +1,13 @@ +using System; + +namespace Discord +{ + internal static class EventExtensions + { + public static void Raise(this EventHandler eventHandler, object sender) + => eventHandler?.Invoke(sender, EventArgs.Empty); + public static void Raise(this EventHandler eventHandler, object sender, T eventArgs) + where T : EventArgs + => eventHandler?.Invoke(sender, eventArgs); + } +} diff --git a/src/Discord.Net/Helpers/MentionHelper.cs b/src/Discord.Net/Helpers/MentionHelper.cs new file mode 100644 index 000000000..d2e350b2b --- /dev/null +++ b/src/Discord.Net/Helpers/MentionHelper.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Discord +{ + public static class MentionHelper + { + private static readonly Regex _userRegex = new Regex(@"<@!?([0-9]+)>", RegexOptions.Compiled); + private static readonly Regex _channelRegex = new Regex(@"<#([0-9]+)>", RegexOptions.Compiled); + private static readonly Regex _roleRegex = new Regex(@"<@&([0-9]+)>", RegexOptions.Compiled); + + internal static string Mention(IUser user, bool useNickname) => useNickname ? $"<@!{user.Id}>" : $"<@{user.Id}>"; + internal static string Mention(IChannel channel) => $"<#{channel.Id}>"; + internal static string Mention(IRole role) => $"<&{role.Id}>"; + + /// Parses a provided user mention string. + public static ulong ParseUser(string mentionText) + { + mentionText = mentionText.Trim(); + if (mentionText.Length >= 3 && mentionText[0] == '<' && mentionText[1] == '@' && mentionText[mentionText.Length - 1] == '>') + { + if (mentionText.Length >= 4 && mentionText[2] == '!') + mentionText = mentionText.Substring(3, mentionText.Length - 4); //<@!123> + else + mentionText = mentionText.Substring(2, mentionText.Length - 3); //<@123> + + ulong id; + if (ulong.TryParse(mentionText, NumberStyles.None, CultureInfo.InvariantCulture, out id)) + return id; + } + throw new ArgumentException("Invalid mention format", nameof(mentionText)); + } + /// Parses a provided channel mention string. + public static ulong ParseChannel(string mentionText) + { + mentionText = mentionText.Trim(); + if (mentionText.Length >= 3 && mentionText[0] == '<' && mentionText[1] == '#' && mentionText[mentionText.Length - 1] == '>') + { + mentionText = mentionText.Substring(2, mentionText.Length - 3); //<#123> + + ulong id; + if (ulong.TryParse(mentionText, NumberStyles.None, CultureInfo.InvariantCulture, out id)) + return id; + } + throw new ArgumentException("Invalid mention format", nameof(mentionText)); + } + /// Parses a provided role mention string. + public static ulong ParseRole(string mentionText) + { + mentionText = mentionText.Trim(); + if (mentionText.Length >= 4 && mentionText[0] == '<' && mentionText[1] == '@' && mentionText[2] == '&' && mentionText[mentionText.Length - 1] == '>') + { + mentionText = mentionText.Substring(3, mentionText.Length - 4); //<@&123> + + ulong id; + if (ulong.TryParse(mentionText, NumberStyles.None, CultureInfo.InvariantCulture, out id)) + return id; + } + throw new ArgumentException("Invalid mention format", nameof(mentionText)); + } + + /// Gets the ids of all users mentioned in a provided text. + public static IReadOnlyList GetUserMentions(string text) => GetMentions(text, _userRegex).ToArray(); + /// Gets the ids of all channels mentioned in a provided text. + public static IReadOnlyList GetChannelMentions(string text) => GetMentions(text, _channelRegex).ToArray(); + /// Gets the ids of all roles mentioned in a provided text. + public static IReadOnlyList GetRoleMentions(string text) => GetMentions(text, _roleRegex).ToArray(); + private static ImmutableArray.Builder GetMentions(string text, Regex regex) + { + var matches = regex.Matches(text); + var builder = ImmutableArray.CreateBuilder(matches.Count); + foreach (var match in matches.OfType()) + { + ulong id; + if (ulong.TryParse(match.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) + builder.Add(id); + } + return builder; + } + + internal static string CleanUserMentions(string text, API.User[] mentions) + { + return _userRegex.Replace(text, new MatchEvaluator(e => + { + ulong id; + if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) + { + for (int i = 0; i < mentions.Length; i++) + { + var mention = mentions[i]; + if (mention.Id == id) + return '@' + mention.Username; + } + } + return e.Value; + })); + } + internal static string CleanUserMentions(string text, IReadOnlyDictionary users, ImmutableArray.Builder mentions = null) + where T : IGuildUser + { + return _channelRegex.Replace(text, new MatchEvaluator(e => + { + ulong id; + if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) + { + T user; + if (users.TryGetValue(id, out user)) + { + if (users != null) + mentions.Add(user); + if (e.Value[2] == '!' && user.Nickname != null) + return '@' + user.Nickname; + else + return '@' + user.Username; + } + } + return e.Value; + })); + } + internal static string CleanChannelMentions(string text, IReadOnlyDictionary channels, ImmutableArray.Builder mentions = null) + where T : IGuildChannel + { + return _channelRegex.Replace(text, new MatchEvaluator(e => + { + ulong id; + if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) + { + T channel; + if (channels.TryGetValue(id, out channel)) + { + if (channels != null) + mentions.Add(channel); + return '#' + channel.Name; + } + } + return e.Value; + })); + } + internal static string CleanRoleMentions(string text, IReadOnlyDictionary roles, ImmutableArray.Builder mentions = null) + where T : IRole + { + return _channelRegex.Replace(text, new MatchEvaluator(e => + { + ulong id; + if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id)) + { + T role; + if (roles.TryGetValue(id, out role)) + { + if (mentions != null) + mentions.Add(role); + return '@' + role.Name; + } + } + return e.Value; + })); + } + } +} diff --git a/src/Discord.Net/IDiscordClient.cs b/src/Discord.Net/IDiscordClient.cs new file mode 100644 index 000000000..2d583126e --- /dev/null +++ b/src/Discord.Net/IDiscordClient.cs @@ -0,0 +1,37 @@ +using Discord.API; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace Discord +{ + public interface IDiscordClient + { + ISelfUser CurrentUser { get; } + DiscordRawClient BaseClient { get; } + //IMessageQueue MessageQueue { get; } + + Task Login(TokenType tokenType, string token); + Task Logout(); + + Task GetChannel(ulong id); + Task> GetDMChannels(); + + Task> GetConnections(); + + Task GetGuild(ulong id); + Task> GetGuilds(); + Task CreateGuild(string name, IVoiceRegion region, Stream jpegIcon = null); + + Task GetInvite(string inviteIdOrXkcd); + + Task GetUser(ulong id); + Task GetUser(string username, ushort discriminator); + Task GetCurrentUser(); + Task> QueryUsers(string query, int limit); + + Task> GetVoiceRegions(); + Task GetVoiceRegion(string id); + Task GetOptimalVoiceRegion(); + } +} diff --git a/src/Discord.Net/InternalExtensions.cs b/src/Discord.Net/InternalExtensions.cs deleted file mode 100644 index 431eaf144..000000000 --- a/src/Discord.Net/InternalExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Discord -{ - internal static class InternalExtensions - { - public static IUser GetCurrentUser(this IChannel channel) - { - switch (channel.Type) - { - case ChannelType.Text: - case ChannelType.Voice: - return (channel as GuildChannel).Guild.CurrentUser; - default: - return channel.Discord.CurrentUser; - } - } - -/*#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/Enums/LogSeverity.cs b/src/Discord.Net/LogSeverity.cs similarity index 100% rename from src/Discord.Net/Enums/LogSeverity.cs rename to src/Discord.Net/LogSeverity.cs diff --git a/src/Discord.Net/Logging/ILogger.cs b/src/Discord.Net/Logging/ILogger.cs new file mode 100644 index 000000000..787965786 --- /dev/null +++ b/src/Discord.Net/Logging/ILogger.cs @@ -0,0 +1,32 @@ +using System; + +namespace Discord.Logging +{ + public interface ILogger + { + LogSeverity Level { get; } + + void Log(LogSeverity severity, string message, Exception exception = null); + void Log(LogSeverity severity, FormattableString message, Exception exception = null); + + void Error(string message, Exception exception = null); + void Error(FormattableString message, Exception exception = null); + void Error(Exception exception); + + void Warning(string message, Exception exception = null); + void Warning(FormattableString message, Exception exception = null); + void Warning(Exception exception); + + void Info(string message, Exception exception = null); + void Info(FormattableString message, Exception exception = null); + void Info(Exception exception); + + void Verbose(string message, Exception exception = null); + void Verbose(FormattableString message, Exception exception = null); + void Verbose(Exception exception); + + void Debug(string message, Exception exception = null); + void Debug(FormattableString message, Exception exception = null); + void Debug(Exception exception); + } +} diff --git a/src/Discord.Net/Logging/LogManager.cs b/src/Discord.Net/Logging/LogManager.cs index d6cc5f435..5b1e4d14b 100644 --- a/src/Discord.Net/Logging/LogManager.cs +++ b/src/Discord.Net/Logging/LogManager.cs @@ -2,7 +2,7 @@ namespace Discord.Logging { - public class LogManager + internal class LogManager : ILogger { public LogSeverity Level { get; } @@ -13,51 +13,91 @@ namespace Discord.Logging Level = minSeverity; } - public void Log(LogSeverity severity, string source, string message, Exception exception = null) + public void Log(LogSeverity severity, string source, string message, Exception ex = null) { if (severity <= Level) - Message(this, new LogMessageEventArgs(severity, source, message, exception)); + Message(this, new LogMessageEventArgs(severity, source, message, ex)); } - public void Log(LogSeverity severity, string source, FormattableString message, Exception exception = null) + public void Log(LogSeverity severity, string source, FormattableString message, Exception ex = null) { if (severity <= Level) - Message(this, new LogMessageEventArgs(severity, source, message.ToString(), exception)); + Message(this, new LogMessageEventArgs(severity, source, message.ToString(), ex)); + } + void ILogger.Log(LogSeverity severity, string message, Exception ex) + { + if (severity <= Level) + Message(this, new LogMessageEventArgs(severity, "Discord", message, ex)); + } + void ILogger.Log(LogSeverity severity, FormattableString message, Exception ex) + { + if (severity <= Level) + Message(this, new LogMessageEventArgs(severity, "Discord", message.ToString(), ex)); } 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) + public void Error(string source, Exception ex = null) => Log(LogSeverity.Error, source, (string)null, ex); + void ILogger.Error(string message, Exception ex) + => Log(LogSeverity.Error, "Discord", message, ex); + void ILogger.Error(FormattableString message, Exception ex) + => Log(LogSeverity.Error, "Discord", message, ex); + void ILogger.Error(Exception ex) + => Log(LogSeverity.Error, "Discord", (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) + public void Warning(string source, Exception ex = null) => Log(LogSeverity.Warning, source, (string)null, ex); + void ILogger.Warning(string message, Exception ex) + => Log(LogSeverity.Warning, "Discord", message, ex); + void ILogger.Warning(FormattableString message, Exception ex) + => Log(LogSeverity.Warning, "Discord", message, ex); + void ILogger.Warning(Exception ex) + => Log(LogSeverity.Warning, "Discord", (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) + public void Info(string source, Exception ex = null) => Log(LogSeverity.Info, source, (string)null, ex); + void ILogger.Info(string message, Exception ex) + => Log(LogSeverity.Info, "Discord", message, ex); + void ILogger.Info(FormattableString message, Exception ex) + => Log(LogSeverity.Info, "Discord", message, ex); + void ILogger.Info(Exception ex) + => Log(LogSeverity.Info, "Discord", (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) + public void Verbose(string source, Exception ex = null) => Log(LogSeverity.Verbose, source, (string)null, ex); + void ILogger.Verbose(string message, Exception ex) + => Log(LogSeverity.Verbose, "Discord", message, ex); + void ILogger.Verbose(FormattableString message, Exception ex) + => Log(LogSeverity.Verbose, "Discord", message, ex); + void ILogger.Verbose(Exception ex) + => Log(LogSeverity.Verbose, "Discord", (string)null, ex); public void Debug(string source, string message, Exception ex = null) => Log(LogSeverity.Debug, source, message, ex); public void Debug(string source, FormattableString message, Exception ex = null) => Log(LogSeverity.Debug, source, message, ex); - public void Debug(string source, Exception ex) - => Log(LogSeverity.Debug, source, (string)null, ex); + public void Debug(string source, Exception ex = null) + => Log(LogSeverity.Debug, source, (string)null, ex); + void ILogger.Debug(string message, Exception ex) + => Log(LogSeverity.Debug, "Discord", message, ex); + void ILogger.Debug(FormattableString message, Exception ex) + => Log(LogSeverity.Debug, "Discord", message, ex); + void ILogger.Debug(Exception ex) + => Log(LogSeverity.Debug, "Discord", (string)null, ex); 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 f64520591..274655948 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 + internal class Logger { private readonly LogManager _manager; diff --git a/src/Discord.Net/MessageQueue.cs b/src/Discord.Net/MessageQueue.cs deleted file mode 100644 index 804784bc5..000000000 --- a/src/Discord.Net/MessageQueue.cs +++ /dev/null @@ -1,287 +0,0 @@ -using Discord.API.Rest; -using Discord.Logging; -using Discord.Net; -using Discord.Net.Rest; -using System; -using System.Collections.Concurrent; -using System.Net; -using System.Threading; -using System.Threading.Tasks; - - -namespace Discord -{ - /// Manages an outgoing message queue for DiscordClient. - 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(TaskCompletionSource promise, Message message, string newText) - { - Promise = promise; - Message = message; - NewText = newText; - } - } - private struct MessageDelete - { - public readonly TaskCompletionSource Promise; - public readonly Message Message; - - public MessageDelete(TaskCompletionSource promise, Message message) - { - Promise = promise; - Message = message; - } - } - - private const int WarningStart = 30; - - private readonly RestClient _rest; - private readonly Logger _logger; - private readonly ConcurrentQueue _pendingSends; - private readonly ConcurrentQueue _pendingEdits; - 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; - - internal MessageQueue(RestClient rest, Logger logger) - { - _rest = rest; - _logger = logger; - _nextWarning = WarningStart; - - _connectionLock = new SemaphoreSlim(1, 1); - _pendingSends = new ConcurrentQueue(); - _pendingEdits = new ConcurrentQueue(); - _pendingDeletes = new ConcurrentQueue(); - } - protected virtual void Dispose(bool disposing) - { - if (!_isDisposed) - { - if (disposing) - _connectionLock.Dispose(); - _isDisposed = true; - } - } - public void Dispose() => Dispose(true); - - internal async Task Start(CancellationToken cancelToken) - { - await _connectionLock.WaitAsync().ConfigureAwait(false); - try - { - await StartInternal(cancelToken).ConfigureAwait(false); - } - finally { _connectionLock.Release(); } - } - internal async Task StartInternal(CancellationToken cancelToken) - { - 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 () => - { - try - { - while (!cancelToken.IsCancellationRequested) - { - MessageSend item; - while (_pendingSends.TryDequeue(out item)) - { - try - { - var request = new CreateMessageRequest(item.Channel.Id) - { - Content = item.Text, - IsTTS = item.IsTTS - }; - var response = await _rest.Send(request).ConfigureAwait(false); - 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); - } - } - catch (OperationCanceledException) { } - }); - } - private Task RunEditQueue(CancellationToken cancelToken) - { - return Task.Run(async () => - { - try - { - while (!cancelToken.IsCancellationRequested) - { - MessageEdit item; - while (_pendingEdits.TryDequeue(out item)) - { - var msg = item.Message; - //if (msg.State != EntityState.Deleted) - //{ - try - { - var request = new ModifyMessageRequest(msg.Channel.Id, msg.Id) - { - Content = item.NewText - }; - await _rest.Send(request).ConfigureAwait(false); - item.Promise.SetResult(null); - } - catch (Exception ex) { item.Promise.SetException(ex); } - //} - DecrementCount(); - } - await Task.Delay(DiscordConfig.MessageQueueInterval).ConfigureAwait(false); - } - } - catch (OperationCanceledException) { } - }); - } - private Task RunDeleteQueue(CancellationToken cancelToken) - { - return Task.Run(async () => - { - try - { - while (!cancelToken.IsCancellationRequested) - { - MessageDelete item; - while (_pendingDeletes.TryDequeue(out item)) - { - 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); - item.Promise.SetResult(null); - } - catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } //Ignore - catch (Exception ex) { item.Promise.SetException(ex); } - //} - DecrementCount(); - } - - await Task.Delay(DiscordConfig.MessageQueueInterval).ConfigureAwait(false); - } - } - catch (OperationCanceledException) { } - }); - } - - private void IncrementCount() - { - int count = Interlocked.Increment(ref _count); - if (count >= _nextWarning) - { - _nextWarning <<= 1; - int sendCount = _pendingSends.Count; - int editCount = _pendingEdits.Count; - int deleteCount = _pendingDeletes.Count; - count = sendCount + editCount + deleteCount; //May not add up due to async - _logger.Warning($"Queue is backed up, currently at {count} actions ({sendCount} sends, {editCount} edits, {deleteCount} deletes)."); - } - else if (count < WarningStart) //Reset once the problem is solved - _nextWarning = WarningStart; - } - private void DecrementCount() - { - int count = Interlocked.Decrement(ref _count); - if (count < (WarningStart / 2)) //Reset once the problem is solved - _nextWarning = WarningStart; - } - - /// Clears all queued message sends/edits/deletes. - public void Clear() - { - MessageSend send; - MessageEdit edit; - MessageDelete delete; - - while (_pendingSends.TryDequeue(out send)) - DecrementCount(); - while (_pendingEdits.TryDequeue(out edit)) - DecrementCount(); - while (_pendingDeletes.TryDequeue(out delete)) - DecrementCount(); - } - } -} diff --git a/src/Discord.Net/Net/JsonConverters/ChannelTypeConverter.cs b/src/Discord.Net/Net/Converters/ChannelTypeConverter.cs similarity index 97% rename from src/Discord.Net/Net/JsonConverters/ChannelTypeConverter.cs rename to src/Discord.Net/Net/Converters/ChannelTypeConverter.cs index 4299df7bf..95c4479df 100644 --- a/src/Discord.Net/Net/JsonConverters/ChannelTypeConverter.cs +++ b/src/Discord.Net/Net/Converters/ChannelTypeConverter.cs @@ -1,7 +1,7 @@ using Newtonsoft.Json; using System; -namespace Discord.Net.JsonConverters +namespace Discord.Net.Converters { public class ChannelTypeConverter : JsonConverter { diff --git a/src/Discord.Net/Net/JsonConverters/ImageConverter.cs b/src/Discord.Net/Net/Converters/ImageConverter.cs similarity index 96% rename from src/Discord.Net/Net/JsonConverters/ImageConverter.cs rename to src/Discord.Net/Net/Converters/ImageConverter.cs index bdbfa6915..cf501050e 100644 --- a/src/Discord.Net/Net/JsonConverters/ImageConverter.cs +++ b/src/Discord.Net/Net/Converters/ImageConverter.cs @@ -2,7 +2,7 @@ using System; using System.IO; -namespace Discord.Net.JsonConverters +namespace Discord.Net.Converters { public class ImageConverter : JsonConverter { diff --git a/src/Discord.Net/Net/JsonConverters/NullableUInt64Converter.cs b/src/Discord.Net/Net/Converters/NullableUInt64Converter.cs similarity index 96% rename from src/Discord.Net/Net/JsonConverters/NullableUInt64Converter.cs rename to src/Discord.Net/Net/Converters/NullableUInt64Converter.cs index 33c7c8ce7..e28460abc 100644 --- a/src/Discord.Net/Net/JsonConverters/NullableUInt64Converter.cs +++ b/src/Discord.Net/Net/Converters/NullableUInt64Converter.cs @@ -2,7 +2,7 @@ using System; using System.Globalization; -namespace Discord.Net.JsonConverters +namespace Discord.Net.Converters { public class NullableUInt64Converter : JsonConverter { diff --git a/src/Discord.Net/Net/JsonConverters/PermissionTargetConverter.cs b/src/Discord.Net/Net/Converters/PermissionTargetConverter.cs similarity index 97% rename from src/Discord.Net/Net/JsonConverters/PermissionTargetConverter.cs rename to src/Discord.Net/Net/Converters/PermissionTargetConverter.cs index 21a8ed8db..a7ef55409 100644 --- a/src/Discord.Net/Net/JsonConverters/PermissionTargetConverter.cs +++ b/src/Discord.Net/Net/Converters/PermissionTargetConverter.cs @@ -1,7 +1,7 @@ using Newtonsoft.Json; using System; -namespace Discord.Net.JsonConverters +namespace Discord.Net.Converters { public class PermissionTargetConverter : JsonConverter { diff --git a/src/Discord.Net/Net/JsonConverters/StringEntityConverter.cs b/src/Discord.Net/Net/Converters/StringEntityConverter.cs similarity index 95% rename from src/Discord.Net/Net/JsonConverters/StringEntityConverter.cs rename to src/Discord.Net/Net/Converters/StringEntityConverter.cs index b19b5977b..49c52bd9d 100644 --- a/src/Discord.Net/Net/JsonConverters/StringEntityConverter.cs +++ b/src/Discord.Net/Net/Converters/StringEntityConverter.cs @@ -1,7 +1,7 @@ using Newtonsoft.Json; using System; -namespace Discord.Net.JsonConverters +namespace Discord.Net.Converters { public class StringEntityConverter : JsonConverter { diff --git a/src/Discord.Net/Net/JsonConverters/UInt64ArrayConverter.cs b/src/Discord.Net/Net/Converters/UInt64ArrayConverter.cs similarity index 97% rename from src/Discord.Net/Net/JsonConverters/UInt64ArrayConverter.cs rename to src/Discord.Net/Net/Converters/UInt64ArrayConverter.cs index 4b03f6fa3..f57e3427b 100644 --- a/src/Discord.Net/Net/JsonConverters/UInt64ArrayConverter.cs +++ b/src/Discord.Net/Net/Converters/UInt64ArrayConverter.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.Globalization; -namespace Discord.Net.JsonConverters +namespace Discord.Net.Converters { internal class UInt64ArrayConverter : JsonConverter { diff --git a/src/Discord.Net/Net/JsonConverters/UInt64Converter.cs b/src/Discord.Net/Net/Converters/UInt64Converter.cs similarity index 95% rename from src/Discord.Net/Net/JsonConverters/UInt64Converter.cs rename to src/Discord.Net/Net/Converters/UInt64Converter.cs index 49c21564a..4983759ab 100644 --- a/src/Discord.Net/Net/JsonConverters/UInt64Converter.cs +++ b/src/Discord.Net/Net/Converters/UInt64Converter.cs @@ -2,7 +2,7 @@ using System; using System.Globalization; -namespace Discord.Net.JsonConverters +namespace Discord.Net.Converters { public class UInt64Converter : JsonConverter { diff --git a/src/Discord.Net/Net/JsonConverters/UInt64EntityConverter.cs b/src/Discord.Net/Net/Converters/UInt64EntityConverter.cs similarity index 95% rename from src/Discord.Net/Net/JsonConverters/UInt64EntityConverter.cs rename to src/Discord.Net/Net/Converters/UInt64EntityConverter.cs index 84945a672..6a0705e3a 100644 --- a/src/Discord.Net/Net/JsonConverters/UInt64EntityConverter.cs +++ b/src/Discord.Net/Net/Converters/UInt64EntityConverter.cs @@ -1,7 +1,7 @@ using Newtonsoft.Json; using System; -namespace Discord.Net.JsonConverters +namespace Discord.Net.Converters { public class UInt64EntityConverter : JsonConverter { diff --git a/src/Discord.Net/Net/JsonConverters/UserStatusConverter.cs b/src/Discord.Net/Net/Converters/UserStatusConverter.cs similarity index 97% rename from src/Discord.Net/Net/JsonConverters/UserStatusConverter.cs rename to src/Discord.Net/Net/Converters/UserStatusConverter.cs index a60d75f75..7ed690421 100644 --- a/src/Discord.Net/Net/JsonConverters/UserStatusConverter.cs +++ b/src/Discord.Net/Net/Converters/UserStatusConverter.cs @@ -1,7 +1,7 @@ using Newtonsoft.Json; using System; -namespace Discord.Net.JsonConverters +namespace Discord.Net.Converters { public class UserStatusConverter : JsonConverter { diff --git a/src/Discord.Net/Net/Rest/DefaultRestEngine.cs b/src/Discord.Net/Net/Rest/DefaultRestClient.cs similarity index 67% rename from src/Discord.Net/Net/Rest/DefaultRestEngine.cs rename to src/Discord.Net/Net/Rest/DefaultRestClient.cs index 84ddfbbeb..3ffe0361f 100644 --- a/src/Discord.Net/Net/Rest/DefaultRestEngine.cs +++ b/src/Discord.Net/Net/Rest/DefaultRestClient.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json; using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net; @@ -10,7 +11,7 @@ using System.Threading.Tasks; namespace Discord.Net.Rest { - public class DefaultRestEngine : IRestEngine + public class DefaultRestClient : IRestClient { private const int HR_SECURECHANNELFAILED = -2146233079; @@ -19,7 +20,7 @@ namespace Discord.Net.Rest protected readonly CancellationToken _cancelToken; protected bool _isDisposed; - public DefaultRestEngine(string baseUrl, CancellationToken cancelToken) + public DefaultRestClient(string baseUrl, CancellationToken cancelToken) { _baseUrl = baseUrl; _cancelToken = cancelToken; @@ -31,7 +32,6 @@ namespace Discord.Net.Rest UseProxy = false, PreAuthenticate = false }); - SetHeader("accept-encoding", "gzip,deflate"); } protected virtual void Dispose(bool disposing) { @@ -53,32 +53,46 @@ namespace Discord.Net.Rest _client.DefaultRequestHeaders.Add(key, value); } - public async Task Send(IRestRequest request) + public async Task Send(string method, string endpoint, string json = null) { - string uri = Path.Combine(_baseUrl, request.Endpoint); - using (var restRequest = new HttpRequestMessage(GetMethod(request.Method), uri)) + string uri = Path.Combine(_baseUrl, endpoint); + using (var restRequest = new HttpRequestMessage(GetMethod(method), uri)) { - object payload = request.Payload; - if (payload != null) - restRequest.Content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); + if (json != null) + restRequest.Content = new StringContent(JsonConvert.SerializeObject(json), Encoding.UTF8, "application/json"); return await SendInternal(restRequest, _cancelToken).ConfigureAwait(false); } } - public async Task Send(IRestFileRequest request) + public async Task Send(string method, string endpoint, IReadOnlyDictionary multipartParams) { - string uri = Path.Combine(_baseUrl, request.Endpoint); - using (var restRequest = new HttpRequestMessage(GetMethod(request.Method), uri)) + string uri = Path.Combine(_baseUrl, endpoint); + using (var restRequest = new HttpRequestMessage(GetMethod(method), uri)) { var content = new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)); - var mpParameters = request.MultipartParameters; - if (mpParameters != null) + if (multipartParams != null) { - foreach (var p in mpParameters) - content.Add(new StringContent(p.Value), p.Key); - + foreach (var p in multipartParams) + { + switch (p.Value) + { + case string value: + content.Add(new StringContent(value), p.Key); + break; + case byte[] value: + content.Add(new ByteArrayContent(value), p.Key); + break; + case Stream value: + content.Add(new StreamContent(value), p.Key); + break; + case MultipartFile value: + content.Add(new StreamContent(value.Stream), value.Filename, p.Key); + break; + default: + throw new InvalidOperationException($"Unsupported param type \"{p.Value.GetType().Name}\""); + } + } } - content.Add(new StreamContent(request.Stream), "file", request.Filename); restRequest.Content = content; return await SendInternal(restRequest, _cancelToken).ConfigureAwait(false); } diff --git a/src/Discord.Net/Net/Rest/IMessageQueue.cs b/src/Discord.Net/Net/Rest/IMessageQueue.cs new file mode 100644 index 000000000..a61131ed8 --- /dev/null +++ b/src/Discord.Net/Net/Rest/IMessageQueue.cs @@ -0,0 +1,7 @@ +namespace Discord.Net.Rest +{ + public interface IMessageQueue + { + int Count { get; } + } +} diff --git a/src/Discord.Net/Net/Rest/IRestClient.cs b/src/Discord.Net/Net/Rest/IRestClient.cs new file mode 100644 index 000000000..c340c7c79 --- /dev/null +++ b/src/Discord.Net/Net/Rest/IRestClient.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace Discord.Net.Rest +{ + public interface IRestClient + { + void SetHeader(string key, string value); + + Task Send(string method, string endpoint, string json = null); + Task Send(string method, string endpoint, IReadOnlyDictionary multipartParams); + } +} diff --git a/src/Discord.Net/Net/Rest/IRestEngine.cs b/src/Discord.Net/Net/Rest/IRestEngine.cs deleted file mode 100644 index e086d79a0..000000000 --- a/src/Discord.Net/Net/Rest/IRestEngine.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; - -namespace Discord.Net.Rest -{ - public interface IRestEngine : IDisposable - { - void SetHeader(string key, string value); - - Task Send(IRestRequest request); - Task Send(IRestFileRequest request); - } -} diff --git a/src/Discord.Net/Net/Rest/IRestRequest.cs b/src/Discord.Net/Net/Rest/IRestRequest.cs deleted file mode 100644 index 0ec7b9a32..000000000 --- a/src/Discord.Net/Net/Rest/IRestRequest.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using System.IO; - -namespace Discord.Net.Rest -{ - public interface IRestRequest - { - string Method { get; } - string Endpoint { get; } - object Payload { get; } - } - public interface IRestRequest : IRestRequest - where TResponse : class - { - } - - public interface IRestFileRequest : IRestRequest - { - string Filename { get; } - Stream Stream { get; } - IReadOnlyList MultipartParameters { get; } - } - public interface IRestFileRequest : IRestFileRequest, IRestRequest - where TResponse : class - { - } -} diff --git a/src/Discord.Net/Net/Rest/MultipartFile.cs b/src/Discord.Net/Net/Rest/MultipartFile.cs new file mode 100644 index 000000000..f7244afd7 --- /dev/null +++ b/src/Discord.Net/Net/Rest/MultipartFile.cs @@ -0,0 +1,16 @@ +using System.IO; + +namespace Discord.Net.Rest +{ + struct MultipartFile + { + public Stream Stream { get; } + public string Filename { get; } + + public MultipartFile(Stream stream, string filename) + { + Stream = stream; + Filename = filename; + } + } +} diff --git a/src/Discord.Net/Net/Rest/RestClient.cs b/src/Discord.Net/Net/Rest/RestClient.cs deleted file mode 100644 index 592a99d3d..000000000 --- a/src/Discord.Net/Net/Rest/RestClient.cs +++ /dev/null @@ -1,98 +0,0 @@ -using Discord.Net.JsonConverters; -using Newtonsoft.Json; -using System; -using System.Diagnostics; -using System.IO; -using System.Threading.Tasks; - -namespace Discord.Net.Rest -{ - public class RestClient - { - internal event EventHandler SentRequest; - - private readonly IRestEngine _engine; - private readonly JsonSerializer _serializer; - - internal RestClient(IRestEngine engine) - { - _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()); - } - public void Dispose() => _engine.Dispose(); - - public void SetHeader(string key, string value) => _engine.SetHeader(key, value); - - public async Task Send(IRestRequest request) - where TResponse : 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(); - - SentRequest(this, new SentRequestEventArgs(request, responseObj, ToMilliseconds(stopwatch))); - return responseObj; - } - public async Task Send(IRestRequest request) - { - if (request == null) throw new ArgumentNullException(nameof(request)); - - 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 TResponse : 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(); - - SentRequest(this, new SentRequestEventArgs(request, responseObj, ToMilliseconds(stopwatch))); - return responseObj; - } - public async Task Send(IRestFileRequest request) - { - if (request == null) throw new ArgumentNullException(nameof(request)); - - var stopwatch = Stopwatch.StartNew(); - await _engine.Send(request).ConfigureAwait(false); - stopwatch.Stop(); - - SentRequest(this, new SentRequestEventArgs(request, null, ToMilliseconds(stopwatch))); - } - - 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); - } - - 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 index 942720ffb..cf3ee0846 100644 --- a/src/Discord.Net/Net/Rest/RestClientProvider.cs +++ b/src/Discord.Net/Net/Rest/RestClientProvider.cs @@ -2,5 +2,5 @@ namespace Discord.Net.Rest { - public delegate IRestEngine RestClientProvider(string baseUrl, CancellationToken cancelToken); + public delegate IRestClient RestClientProvider(string baseUrl, CancellationToken cancelToken); } diff --git a/src/Discord.Net/Net/Rest/RestParameter.cs b/src/Discord.Net/Net/Rest/RestParameter.cs deleted file mode 100644 index 5fac47bf8..000000000 --- a/src/Discord.Net/Net/Rest/RestParameter.cs +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index 25f433d25..000000000 --- a/src/Discord.Net/Net/Rest/SentRequestEventArgs.cs +++ /dev/null @@ -1,16 +0,0 @@ -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/WebSockets/BinaryMessageEventArgs.cs b/src/Discord.Net/Net/WebSockets/BinaryMessageEventArgs.cs deleted file mode 100644 index 3fd4425fa..000000000 --- a/src/Discord.Net/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/src/Discord.Net/Net/WebSockets/DefaultWebSocketEngine.cs b/src/Discord.Net/Net/WebSockets/DefaultWebSocketEngine.cs deleted file mode 100644 index d9486c751..000000000 --- a/src/Discord.Net/Net/WebSockets/DefaultWebSocketEngine.cs +++ /dev/null @@ -1,180 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.ComponentModel; -using System.IO; -using System.Net.WebSockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Discord.Net.WebSockets -{ - public class DefaultWebSocketEngine : IWebSocketEngine - { - 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 { }; - - protected readonly ConcurrentQueue _sendQueue; - protected readonly ClientWebSocket _client; - protected Task _receiveTask, _sendTask; - protected CancellationTokenSource _cancelToken; - protected bool _isDisposed; - - public DefaultWebSocketEngine() - { - _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) - { - await Disconnect().ConfigureAwait(false); - - _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)) { } - - _client.Abort(); - - var receiveTask = _receiveTask ?? TaskHelper.CompletedTask; - var sendTask = _sendTask ?? TaskHelper.CompletedTask; - await Task.WhenAll(receiveTask, sendTask).ConfigureAwait(false); - } - - 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 () => - { - var buffer = new ArraySegment(new byte[ReceiveChunkSize]); - var stream = new MemoryStream(); - - try - { - while (!cancelToken.IsCancellationRequested) - { - WebSocketReceiveResult result = null; - do - { - if (cancelToken.IsCancellationRequested) return; - - try - { - result = await _client.ReceiveAsync(buffer, cancelToken).ConfigureAwait(false); - } - catch (Win32Exception ex) when (ex.HResult == HR_TIMEOUT) - { - throw new Exception($"Connection timed out."); - } - - if (result.MessageType == WebSocketMessageType.Close) - throw new WebSocketException((int)result.CloseStatus.Value, result.CloseStatusDescription); - else - stream.Write(buffer.Array, buffer.Offset, buffer.Count); - - } - while (result == null || !result.EndOfMessage); - - var array = stream.ToArray(); - if (result.MessageType == WebSocketMessageType.Binary) - BinaryMessage(this, new BinaryMessageEventArgs(array)); - else if (result.MessageType == WebSocketMessageType.Text) - { - string text = Encoding.UTF8.GetString(array, 0, array.Length); - TextMessage(this, new TextMessageEventArgs(text)); - } - - stream.Position = 0; - stream.SetLength(0); - } - } - catch (OperationCanceledException) { } - }); - } - - //TODO: Check this code - private Task SendAsync(CancellationToken cancelToken) - { - return Task.Run(async () => - { - byte[] bytes = new byte[SendChunkSize]; - - try - { - while (!cancelToken.IsCancellationRequested) - { - string json; - while (_sendQueue.TryDequeue(out json)) - { - int byteCount = Encoding.UTF8.GetBytes(json, 0, json.Length, bytes, 0); - int frameCount = (int)Math.Ceiling((double)byteCount / SendChunkSize); - - int offset = 0; - for (int i = 0; i < frameCount; i++, offset += SendChunkSize) - { - bool isLast = i == (frameCount - 1); - - int count; - if (isLast) - count = byteCount - (i * SendChunkSize); - else - count = SendChunkSize; - - try - { - await _client.SendAsync(new ArraySegment(bytes, offset, count), WebSocketMessageType.Text, isLast, cancelToken).ConfigureAwait(false); - } - catch (Win32Exception ex) when (ex.HResult == HR_TIMEOUT) - { - return; - } - } - } - await Task.Delay(DiscordConfig.WebSocketQueueInterval, cancelToken).ConfigureAwait(false); - } - } - catch (OperationCanceledException) { } - }); - } - } -} diff --git a/src/Discord.Net/Net/WebSockets/GatewaySocket.cs b/src/Discord.Net/Net/WebSockets/GatewaySocket.cs deleted file mode 100644 index 3e841de89..000000000 --- a/src/Discord.Net/Net/WebSockets/GatewaySocket.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace Discord.Net.WebSockets -{ - public class GatewaySocket : WebSocket - { - public event EventHandler ReceivedDispatch = delegate { }; - - public ConnectionState State { get; } - public string Host { get; } - public string SessionId { get; } - - internal GatewaySocket(IWebSocketEngine engine) - : base(engine) - { - } - - public void SetHeader(string key, string value) => _engine.SetHeader(key, value); - - internal Task Connect(CancellationToken cancelToken) - { - return Task.Delay(0); - } - internal Task Disconnect() - { - return Task.Delay(0); - } - - public void SendIdentify(string 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 deleted file mode 100644 index b43109276..000000000 --- a/src/Discord.Net/Net/WebSockets/IWebSocketEngine.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Discord.Net.WebSockets -{ - public interface IWebSocketEngine : IDisposable - { - event EventHandler BinaryMessage; - event EventHandler TextMessage; - - 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/TextMessageEventArgs.cs b/src/Discord.Net/Net/WebSockets/TextMessageEventArgs.cs deleted file mode 100644 index e4e186044..000000000 --- a/src/Discord.Net/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/src/Discord.Net/Net/WebSockets/WebSocket.cs b/src/Discord.Net/Net/WebSockets/WebSocket.cs deleted file mode 100644 index ed533883a..000000000 --- a/src/Discord.Net/Net/WebSockets/WebSocket.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; - -namespace Discord.Net.WebSockets -{ - public class WebSocket : IDisposable - { - protected readonly IWebSocketEngine _engine; - protected bool _isDisposed; - - internal WebSocket(IWebSocketEngine engine) - { - _engine = engine; - } - - protected virtual void Dispose(bool disposing) - { - if (!_isDisposed) - { - 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 deleted file mode 100644 index 676c0ba6e..000000000 --- a/src/Discord.Net/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/src/Discord.Net/Net/WebSockets/WebSocketProvider.cs b/src/Discord.Net/Net/WebSockets/WebSocketProvider.cs deleted file mode 100644 index 7e7652dbc..000000000 --- a/src/Discord.Net/Net/WebSockets/WebSocketProvider.cs +++ /dev/null @@ -1,6 +0,0 @@ -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 index b562e546b..26e8c428e 100644 --- a/src/Discord.Net/Properties/AssemblyInfo.cs +++ b/src/Discord.Net/Properties/AssemblyInfo.cs @@ -2,17 +2,15 @@ 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: AssemblyDescription("An unofficial .Net API wrapper for the Discord client.")] +[assembly: AssemblyCompany("RogueException")] +[assembly: AssemblyCopyright("Copyright © RogueException 2016")] [assembly: ComVisible(false)] - -[assembly: Guid("c6a50d24-cbd3-4e76-852c-4dca60bbd608")] +[assembly: Guid("62ea817d-c945-4100-ba21-9dfb139d2868")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyInformationalVersion("1.0.0-alpha1")] + diff --git a/src/Discord.Net/TaskHelper.cs b/src/Discord.Net/TaskHelper.cs deleted file mode 100644 index 17ecc4615..000000000 --- a/src/Discord.Net/TaskHelper.cs +++ /dev/null @@ -1,18 +0,0 @@ -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/TokenType.cs b/src/Discord.Net/TokenType.cs new file mode 100644 index 000000000..519f4bf0b --- /dev/null +++ b/src/Discord.Net/TokenType.cs @@ -0,0 +1,9 @@ +namespace Discord +{ + public enum TokenType + { + User, + Bearer, + Bot, + } +} diff --git a/src/Discord.Net/project.json b/src/Discord.Net/project.json index 4aa7cd55c..c47cb1411 100644 --- a/src/Discord.Net/project.json +++ b/src/Discord.Net/project.json @@ -1,39 +1,14 @@ { - "version": "1.0.0-alpha1", - "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" - }, - - "compilationOptions": { - "allowUnsafe": true - }, - "dependencies": { "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-*" + "System.Collections.Immutable": "1.1.37" }, "frameworks": { - "netstandard1.4": { - "imports": "dotnet5.5" - } + "net461": { } + }, + + "runtimes": { + "win": { } } } \ No newline at end of file