@@ -26,6 +26,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net", "src\Discord. | |||
EndProject | |||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Commands", "src\Discord.Net.Commands.Net45\Discord.Net.Commands.csproj", "{1B5603B4-6F8F-4289-B945-7BAAE523D740}" | |||
EndProject | |||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Modules", "src\Discord.Net.Modules\Discord.Net.Modules.xproj", "{01584E8A-78DA-486F-9EF9-A894E435841B}" | |||
EndProject | |||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Modules", "src\Discord.Net.Modules.Net45\Discord.Net.Modules.csproj", "{3091164F-66AE-4543-A63D-167C1116241D}" | |||
EndProject | |||
Global | |||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
Debug|Any CPU = Debug|Any CPU | |||
@@ -63,6 +67,18 @@ Global | |||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|Any CPU.Build.0 = Debug|Any CPU | |||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{01584E8A-78DA-486F-9EF9-A894E435841B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{01584E8A-78DA-486F-9EF9-A894E435841B}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{01584E8A-78DA-486F-9EF9-A894E435841B}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{01584E8A-78DA-486F-9EF9-A894E435841B}.FullDebug|Any CPU.Build.0 = Debug|Any CPU | |||
{01584E8A-78DA-486F-9EF9-A894E435841B}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{01584E8A-78DA-486F-9EF9-A894E435841B}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{3091164F-66AE-4543-A63D-167C1116241D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{3091164F-66AE-4543-A63D-167C1116241D}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|Any CPU.Build.0 = Debug|Any CPU | |||
{3091164F-66AE-4543-A63D-167C1116241D}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{3091164F-66AE-4543-A63D-167C1116241D}.Release|Any CPU.Build.0 = Release|Any CPU | |||
EndGlobalSection | |||
GlobalSection(SolutionProperties) = preSolution | |||
HideSolutionNode = FALSE | |||
@@ -75,5 +91,7 @@ Global | |||
{855D6B1D-847B-42DA-BE6A-23683EA89511} = {6317A2E6-8E36-4C3E-949B-3F10EC888AB9} | |||
{8D71A857-879A-4A10-859E-5FF824ED6688} = {DF03D4E8-38F6-4FE1-BC52-E38124BE8AFD} | |||
{1B5603B4-6F8F-4289-B945-7BAAE523D740} = {DF03D4E8-38F6-4FE1-BC52-E38124BE8AFD} | |||
{01584E8A-78DA-486F-9EF9-A894E435841B} = {EA68EBE2-51C8-4440-9EF7-D633C90A5D35} | |||
{3091164F-66AE-4543-A63D-167C1116241D} = {DF03D4E8-38F6-4FE1-BC52-E38124BE8AFD} | |||
EndGlobalSection | |||
EndGlobal |
@@ -13,6 +13,6 @@ using System.Runtime.InteropServices; | |||
[assembly: ComVisible(false)] | |||
[assembly: Guid("76ea00e6-ea24-41e1-acb2-639c0313fa80")] | |||
[assembly: AssemblyVersion("0.8.0.0")] | |||
[assembly: AssemblyFileVersion("0.8.0.0")] | |||
[assembly: AssemblyVersion("0.8.1.0")] | |||
[assembly: AssemblyFileVersion("0.8.1.0")] | |||
@@ -1,5 +1,5 @@ | |||
{ | |||
"version": "0.8.0-beta1", | |||
"version": "0.8.1-beta1", | |||
"description": "A Discord.Net extension adding basic command support.", | |||
"authors": [ "RogueException" ], | |||
"tags": [ "discord", "discordapp" ], | |||
@@ -13,7 +13,7 @@ | |||
"warningsAsErrors": true | |||
}, | |||
"dependencies": { | |||
"Discord.Net": "0.8.0-beta1" | |||
"Discord.Net": "0.8.1-beta1" | |||
}, | |||
"frameworks": { | |||
"net45": { }, | |||
@@ -0,0 +1,56 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | |||
<PropertyGroup> | |||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |||
<ProjectGuid>{3091164F-66AE-4543-A63D-167C1116241D}</ProjectGuid> | |||
<OutputType>Library</OutputType> | |||
<AppDesignerFolder>Properties</AppDesignerFolder> | |||
<RootNamespace>Discord</RootNamespace> | |||
<AssemblyName>Discord.Net.Commands</AssemblyName> | |||
<FileAlignment>512</FileAlignment> | |||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> | |||
<UseMSBuildEngine>False</UseMSBuildEngine> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | |||
<DebugSymbols>true</DebugSymbols> | |||
<DebugType>full</DebugType> | |||
<Optimize>false</Optimize> | |||
<OutputPath>bin\Debug\</OutputPath> | |||
<DefineConstants>TRACE;DEBUG;NET45</DefineConstants> | |||
<ErrorReport>prompt</ErrorReport> | |||
<WarningLevel>4</WarningLevel> | |||
<LangVersion>6</LangVersion> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||
<DebugType>pdbonly</DebugType> | |||
<Optimize>true</Optimize> | |||
<OutputPath>bin\Release\</OutputPath> | |||
<DefineConstants>TRACE;NET45</DefineConstants> | |||
<ErrorReport>prompt</ErrorReport> | |||
<WarningLevel>4</WarningLevel> | |||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> | |||
<LangVersion>6</LangVersion> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<Reference Include="System" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\Discord.Net.Net45\Discord.Net.csproj"> | |||
<Project>{8d71a857-879a-4a10-859e-5ff824ed6688}</Project> | |||
<Name>Discord.Net</Name> | |||
</ProjectReference> | |||
</ItemGroup> | |||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | |||
Other similar extension points exist, see Microsoft.Common.targets. | |||
<Target Name="BeforeBuild"> | |||
</Target> | |||
<Target Name="AfterBuild"> | |||
</Target> | |||
--> | |||
</Project> |
@@ -0,0 +1,18 @@ | |||
using System.Reflection; | |||
using System.Runtime.InteropServices; | |||
[assembly: AssemblyTitle("Discord.Net.Modules")] | |||
[assembly: AssemblyDescription("A Discord.Net extension adding basic plugin support.")] | |||
[assembly: AssemblyConfiguration("")] | |||
[assembly: AssemblyCompany("RogueException")] | |||
[assembly: AssemblyProduct("Discord.Net.Modules")] | |||
[assembly: AssemblyCopyright("Copyright © 2015")] | |||
[assembly: AssemblyTrademark("")] | |||
[assembly: AssemblyCulture("")] | |||
[assembly: ComVisible(false)] | |||
[assembly: Guid("76ea00e6-ea24-41e1-acb2-639c0313fa80")] | |||
[assembly: AssemblyVersion("0.8.1.0")] | |||
[assembly: AssemblyFileVersion("0.8.1.0")] | |||
@@ -0,0 +1,21 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
<PropertyGroup> | |||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion> | |||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> | |||
</PropertyGroup> | |||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" /> | |||
<PropertyGroup Label="Globals"> | |||
<ProjectGuid>01584e8a-78da-486f-9ef9-a894e435841b</ProjectGuid> | |||
<RootNamespace>Discord</RootNamespace> | |||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath> | |||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath> | |||
</PropertyGroup> | |||
<PropertyGroup> | |||
<SchemaVersion>2.0</SchemaVersion> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> | |||
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild> | |||
</PropertyGroup> | |||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" /> | |||
</Project> |
@@ -0,0 +1,22 @@ | |||
{ | |||
"version": "0.8.1-beta1", | |||
"description": "A Discord.Net extension adding basic plugin support.", | |||
"authors": [ "RogueException" ], | |||
"tags": [ "discord", "discordapp" ], | |||
"projectUrl": "https://github.com/RogueException/Discord.Net", | |||
"licenseUrl": "http://opensource.org/licenses/MIT", | |||
"repository": { | |||
"type": "git", | |||
"url": "git://github.com/RogueException/Discord.Net" | |||
}, | |||
"compilationOptions": { | |||
"warningsAsErrors": true | |||
}, | |||
"dependencies": { | |||
"Discord.Net": "0.8.1-beta1" | |||
}, | |||
"frameworks": { | |||
"net45": { }, | |||
"dnx451": { } | |||
} | |||
} |
@@ -13,5 +13,5 @@ using System.Runtime.InteropServices; | |||
[assembly: ComVisible(false)] | |||
[assembly: Guid("76ea00e6-ea24-41e1-acb2-639c0313fa80")] | |||
[assembly: AssemblyVersion("0.8.0")] | |||
[assembly: AssemblyFileVersion("0.8.0")] | |||
[assembly: AssemblyVersion("0.8.1.0")] | |||
[assembly: AssemblyFileVersion("0.8.1.0")] |
@@ -13,19 +13,22 @@ | |||
public const string Channels = "channels"; | |||
public static string Channel(string channelId) => $"channels/{channelId}"; | |||
public static string ChannelTyping(string channelId) => $"channels/{channelId}/typing"; | |||
public static string ChannelInvites(string channelId) => $"channels/{channelId}/invites"; | |||
public static string ChannelMessages(string channelId) => $"channels/{channelId}/messages"; | |||
public static string ChannelMessages(string channelId, int limit) => $"channels/{channelId}/messages?limit={limit}"; | |||
public static string ChannelMessages(string channelId, int limit, string beforeId) => $"channels/{channelId}/messages?limit={limit}&before={beforeId}"; | |||
public static string ChannelMessage(string channelId, string msgId) => $"channels/{channelId}/messages/{msgId}"; | |||
public static string ChannelMessageAck(string channelId, string msgId) => $"channels/{channelId}/messages/{msgId}/ack"; | |||
public static string ChannelInvites(string channelId) => $"channels/{channelId}/invites"; | |||
public static string ChannelPermission(string channelId, string userOrRoleId) => $"channels/{channelId}/permissions/{userOrRoleId}"; | |||
public static string ChannelTyping(string channelId) => $"channels/{channelId}/typing"; | |||
public const string Servers = "guilds"; | |||
public static string Server(string serverId) => $"guilds/{serverId}"; | |||
public static string ServerBan(string serverId, string userId) => $"guilds/{serverId}/bans/{userId}"; | |||
public static string ServerChannels(string serverId) => $"guilds/{serverId}/channels"; | |||
public static string ServerInvites(string serverId) => $"guilds/{serverId}/invites"; | |||
public static string ServerMember(string serverId, string userId) => $"guilds/{serverId}/members/{userId}"; | |||
public static string ServerBan(string serverId, string userId) => $"guilds/{serverId}/bans/{userId}"; | |||
public static string ServerPrune(string serverId, int days) => $"guilds/{serverId}/prune?days={days}"; | |||
public static string ServerRoles(string serverId) => $"guilds/{serverId}/roles"; | |||
public static string ServerRole(string serverId, string roleId) => $"guilds/{serverId}/roles/{roleId}"; | |||
@@ -34,10 +37,10 @@ | |||
public static string InviteUrl(string inviteId) => $"https://discord.gg/{inviteId}"; | |||
public const string Users = "users"; | |||
public static string UserMe => $"users/@me"; | |||
public static string UserChannels(string userId) => $"users/{userId}/channels"; | |||
public static string UserAvatar(string userId, string avatarId) => $"users/{userId}/avatars/{avatarId}.jpg"; | |||
public static string UserChannels(string userId) => $"users/{userId}/channels"; | |||
public static string UserMe => $"users/@me"; | |||
public const string Voice = "voice"; | |||
public const string VoiceRegions = "voice/regions"; | |||
//public const string VoiceIce = "voice/ice"; | |||
@@ -4,6 +4,7 @@ | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Generic; | |||
namespace Discord.API | |||
{ | |||
@@ -53,6 +54,7 @@ namespace Discord.API | |||
//Get | |||
public class GetInviteResponse : InviteReference { } | |||
public class GetInvitesResponse : List<InviteReference> { } | |||
//Accept | |||
public class AcceptInviteResponse : InviteReference { } | |||
@@ -82,9 +82,20 @@ namespace Discord.API | |||
public IEnumerable<string> Roles; | |||
} | |||
public class PruneUsersResponse | |||
{ | |||
[JsonProperty("pruned")] | |||
public int? Pruned; | |||
} | |||
//Events | |||
internal sealed class MemberAddEvent : MemberInfo { } | |||
internal sealed class MemberUpdateEvent : MemberInfo { } | |||
internal sealed class MemberRemoveEvent : MemberInfo { } | |||
internal sealed class MemberVoiceStateUpdateEvent : VoiceMemberInfo { } | |||
internal sealed class MemberVoiceStateUpdateEvent : VoiceMemberInfo { } | |||
internal sealed class MembersChunkEvent | |||
{ | |||
[JsonProperty("members")] | |||
public MemberInfo[] Members; | |||
} | |||
} |
@@ -125,6 +125,21 @@ namespace Discord.API | |||
//Get | |||
public sealed class GetMessagesResponse : List<MessageInfo> { } | |||
//Commands | |||
internal sealed class GetUsersCommand : WebSocketMessage<GetUsersCommand.Data> | |||
{ | |||
public GetUsersCommand() : base(8) { } | |||
public class Data | |||
{ | |||
[JsonProperty("guild_id")] | |||
public string ServerId; | |||
[JsonProperty("query")] | |||
public string Query; | |||
[JsonProperty("limit")] | |||
public int Limit; | |||
} | |||
} | |||
//Events | |||
internal sealed class MessageCreateEvent : MessageInfo { } | |||
internal sealed class MessageUpdateEvent : MessageInfo { } | |||
@@ -92,11 +92,14 @@ namespace Discord | |||
var request = new ReorderChannelsRequest(channels); | |||
return _rest.Patch(Endpoints.ServerChannels(serverId), request); | |||
} | |||
public Task<GetMessagesResponse> GetMessages(string channelId, int count) | |||
public Task<GetMessagesResponse> GetMessages(string channelId, int count, string beforeMessageId = null) | |||
{ | |||
if (channelId == null) throw new ArgumentNullException(nameof(channelId)); | |||
return _rest.Get<GetMessagesResponse>(Endpoints.ChannelMessages(channelId, count)); | |||
if (beforeMessageId != null) | |||
return _rest.Get<GetMessagesResponse>(Endpoints.ChannelMessages(channelId, count, beforeMessageId)); | |||
else | |||
return _rest.Get<GetMessagesResponse>(Endpoints.ChannelMessages(channelId, count)); | |||
} | |||
//Incidents | |||
@@ -123,6 +126,12 @@ namespace Discord | |||
return _rest.Get<GetInviteResponse>(Endpoints.Invite(inviteIdOrXkcd)); | |||
} | |||
public Task<GetInvitesResponse> GetInvites(string serverId) | |||
{ | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
return _rest.Get<GetInvitesResponse>(Endpoints.ServerInvites(serverId)); | |||
} | |||
public Task<AcceptInviteResponse> AcceptInvite(string inviteId) | |||
{ | |||
if (inviteId == null) throw new ArgumentNullException(nameof(inviteId)); | |||
@@ -136,7 +145,7 @@ namespace Discord | |||
return _rest.Delete(Endpoints.Invite(inviteId)); | |||
} | |||
//Members | |||
//Users | |||
public Task EditUser(string serverId, string userId, bool? mute = null, bool? deaf = null, IEnumerable<string> roles = null) | |||
{ | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
@@ -145,27 +154,37 @@ namespace Discord | |||
var request = new EditMemberRequest { Mute = mute, Deaf = deaf, Roles = roles }; | |||
return _rest.Patch(Endpoints.ServerMember(serverId, userId), request); | |||
} | |||
public Task Kick(string serverId, string userId) | |||
public Task KickUser(string serverId, string userId) | |||
{ | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||
return _rest.Delete(Endpoints.ServerMember(serverId, userId)); | |||
} | |||
public Task Ban(string serverId, string userId) | |||
public Task BanUser(string serverId, string userId) | |||
{ | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||
return _rest.Put(Endpoints.ServerBan(serverId, userId)); | |||
} | |||
public Task Unban(string serverId, string userId) | |||
public Task UnbanUser(string serverId, string userId) | |||
{ | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||
return _rest.Delete(Endpoints.ServerBan(serverId, userId)); | |||
} | |||
public Task<PruneUsersResponse> PruneUsers(string serverId, int days, bool simulate) | |||
{ | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
if (days <= 0) throw new ArgumentOutOfRangeException(nameof(days)); | |||
if (simulate) | |||
return _rest.Get<PruneUsersResponse>(Endpoints.ServerPrune(serverId, days)); | |||
else | |||
return _rest.Post<PruneUsersResponse>(Endpoints.ServerPrune(serverId, days)); | |||
} | |||
//Messages | |||
public Task<SendMessageResponse> SendMessage(string channelId, string message, IEnumerable<string> mentionedUserIds = null, string nonce = null, bool isTTS = false) | |||
@@ -38,7 +38,7 @@ namespace Discord | |||
if (user.Server == null) throw new ArgumentException("Unable to ban a user in a private chat."); | |||
CheckReady(); | |||
return _api.Ban(user.Server.Id, user.Id); | |||
return _api.BanUser(user.Server.Id, user.Id); | |||
} | |||
/// <summary> Unbans a user from the provided server. </summary> | |||
@@ -48,7 +48,7 @@ namespace Discord | |||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||
CheckReady(); | |||
try { await _api.Unban(server.Id, userId).ConfigureAwait(false); } | |||
try { await _api.UnbanUser(server.Id, userId).ConfigureAwait(false); } | |||
catch (HttpException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { } | |||
} | |||
} |
@@ -1,4 +1,5 @@ | |||
using System; | |||
using System.Linq; | |||
using System.Net; | |||
using System.Threading.Tasks; | |||
@@ -10,8 +11,6 @@ namespace Discord | |||
/// <remarks> Supported formats: inviteCode, xkcdCode, https://discord.gg/inviteCode, https://discord.gg/xkcdCode </remarks> | |||
public async Task<Invite> GetInvite(string inviteIdOrXkcd) | |||
{ | |||
//This doesn't work well if it's an invite to a different server! | |||
if (inviteIdOrXkcd == null) throw new ArgumentNullException(nameof(inviteIdOrXkcd)); | |||
CheckReady(); | |||
@@ -26,7 +25,24 @@ namespace Discord | |||
var response = await _api.GetInvite(inviteIdOrXkcd).ConfigureAwait(false); | |||
var invite = new Invite(this, response.Code, response.XkcdPass, response.Guild.Id, response.Inviter?.Id, response.Channel?.Id); | |||
invite.Cache(); //Builds references | |||
return invite; | |||
invite.Update(response); | |||
return invite; | |||
} | |||
/// <summary> Gets all active (non-expired) invites to a provided server. </summary> | |||
public async Task<Invite[]> GetInvites(Server server) | |||
{ | |||
if (server == null) throw new ArgumentNullException(nameof(server)); | |||
CheckReady(); | |||
var response = await _api.GetInvites(server.Id).ConfigureAwait(false); | |||
return response.Select(x => | |||
{ | |||
var invite = new Invite(this, x.Code, x.XkcdPass, x.Guild.Id, x.Inviter?.Id, x.Channel?.Id); | |||
invite.Cache(); //Builds references | |||
invite.Update(x); | |||
return invite; | |||
}).ToArray(); | |||
} | |||
/// <summary> Creates a new invite to the default channel of the provided server. </summary> | |||
@@ -46,7 +46,7 @@ namespace Discord | |||
public const int MaxMessageSize = 2000; | |||
public event EventHandler<MessageEventArgs> MessageReceived; | |||
private void RaiseMessageCreated(Message msg) | |||
private void RaiseMessageReceived(Message msg) | |||
{ | |||
if (MessageReceived != null) | |||
RaiseEvent(nameof(MessageReceived), () => MessageReceived(this, new MessageEventArgs(msg))); | |||
@@ -93,6 +93,7 @@ namespace Discord | |||
{ | |||
if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||
if (text == null) throw new ArgumentNullException(nameof(text)); | |||
if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); | |||
CheckReady(); | |||
return SendMessage(channel, text, false); | |||
@@ -102,6 +103,7 @@ namespace Discord | |||
{ | |||
if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||
if (text == null) throw new ArgumentNullException(nameof(text)); | |||
if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); | |||
CheckReady(); | |||
return SendMessage(channel, text, false); | |||
@@ -111,7 +113,8 @@ namespace Discord | |||
{ | |||
if (user == null) throw new ArgumentNullException(nameof(user)); | |||
if (text == null) throw new ArgumentNullException(nameof(text)); | |||
CheckReady(); | |||
if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); | |||
CheckReady(); | |||
var channel = await CreatePMChannel(user).ConfigureAwait(false); | |||
return await SendMessage(channel, text).ConfigureAwait(false); | |||
@@ -164,6 +167,8 @@ namespace Discord | |||
public Task EditMessage(Message message, string text) | |||
{ | |||
if (message == null) throw new ArgumentNullException(nameof(message)); | |||
if (text == null) throw new ArgumentNullException(nameof(text)); | |||
if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); | |||
CheckReady(); | |||
if (text != null && text.Length > MaxMessageSize) | |||
@@ -210,7 +215,7 @@ namespace Discord | |||
{ | |||
try | |||
{ | |||
var msgs = await _api.GetMessages(channel.Id, count).ConfigureAwait(false); | |||
var msgs = await _api.GetMessages(channel.Id, count, beforeMessageId).ConfigureAwait(false); | |||
return msgs.Select(x => | |||
{ | |||
Message msg = null; | |||
@@ -1,5 +1,4 @@ | |||
using Discord.API; | |||
using System; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading.Tasks; | |||
@@ -85,7 +84,7 @@ namespace Discord | |||
RaiseEvent(nameof(UserRemoved), () => UserRemoved(this, new UserEventArgs(user))); | |||
} | |||
public event EventHandler<UserEventArgs> UserUpdated; | |||
private void RaiseMemberUpdated(User user) | |||
private void RaiseUserUpdated(User user) | |||
{ | |||
if (UserUpdated != null) | |||
RaiseEvent(nameof(UserUpdated), () => UserUpdated(this, new UserEventArgs(user))); | |||
@@ -170,10 +169,51 @@ namespace Discord | |||
if (user == null) throw new ArgumentNullException(nameof(user)); | |||
CheckReady(); | |||
return _api.EditUser(user.Server?.Id, user.Id, mute: mute, deaf: deaf, roles: roles.Select(x => x.Id)); | |||
var serverId = user.Server?.Id; | |||
return _api.EditUser(serverId, user.Id, | |||
mute: mute, deaf: deaf, | |||
roles: roles.Select(x => x.Id).Where(x => x != serverId)); | |||
} | |||
public Task<EditUserResponse> EditProfile(string currentPassword = "", | |||
public Task KickUser(User user) | |||
{ | |||
if (user == null) throw new ArgumentNullException(nameof(user)); | |||
return _api.KickUser(user.Server?.Id, user.Id); | |||
} | |||
public Task BanUser(User user) | |||
{ | |||
if (user == null) throw new ArgumentNullException(nameof(user)); | |||
return _api.BanUser(user.Server?.Id, user.Id); | |||
} | |||
public Task UnbanUser(Server server, string userId) | |||
{ | |||
if (server == null) throw new ArgumentNullException(nameof(server)); | |||
if (userId == null) throw new ArgumentNullException(nameof(userId)); | |||
return _api.UnbanUser(server.Id, userId); | |||
} | |||
public async Task<int> PruneUsers(string serverId, int days, bool simulate = false) | |||
{ | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
if (days <= 0) throw new ArgumentOutOfRangeException(nameof(days)); | |||
CheckReady(); | |||
var response = await _api.PruneUsers(serverId, days, simulate); | |||
return response.Pruned ?? 0; | |||
} | |||
/// <summary>When Config.UseLargeThreshold is enabled, running this command will request the Discord server to provide you with all offline users for a particular server.</summary> | |||
public void RequestOfflineUsers(string serverId) | |||
{ | |||
if (serverId == null) throw new ArgumentNullException(nameof(serverId)); | |||
_dataSocket.SendGetUsers(serverId); | |||
} | |||
public Task EditProfile(string currentPassword = "", | |||
string username = null, string email = null, string password = null, | |||
ImageType avatarType = ImageType.Png, byte[] avatar = null) | |||
{ | |||
@@ -90,7 +90,7 @@ namespace Discord | |||
ChannelUpdated += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client, | |||
$"Channel Updated: {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}"); | |||
MessageReceived += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client, | |||
$"Message Created: {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}/{e.Message?.Id}"); | |||
$"Message Received: {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}/{e.Message?.Id}"); | |||
MessageDeleted += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client, | |||
$"Message Deleted: {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}/{e.Message?.Id}"); | |||
MessageUpdated += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client, | |||
@@ -106,26 +106,26 @@ namespace Discord | |||
UserUnbanned += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client, | |||
$"Unbanned User: {e.Server?.Name ?? "[Private]"}/{e.UserId}"); | |||
UserAdded += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client, | |||
$"User Joined: {e.Server?.Name ?? "[Private]"}/{e.User.Id}"); | |||
$"User Joined: {e.Server?.Name ?? "[Private]"}/{e.User.Name}"); | |||
UserRemoved += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client, | |||
$"User Left: {e.Server?.Name ?? "[Private]"}/{e.User.Id}"); | |||
$"User Left: {e.Server?.Name ?? "[Private]"}/{e.User.Name}"); | |||
UserUpdated += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client, | |||
$"User Updated: {e.Server?.Name ?? "[Private]"}/{e.User.Id}"); | |||
$"User Updated: {e.Server?.Name ?? "[Private]"}/{e.User.Name}"); | |||
UserVoiceStateUpdated += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client, | |||
$"User Updated (Voice State): {e.Server?.Name ?? "[Private]"}/{e.User.Id}"); | |||
$"User Updated (Voice State): {e.Server?.Name ?? "[Private]"}/{e.User.Name}"); | |||
ProfileUpdated += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client, | |||
"Profile Updated"); | |||
} | |||
if (_config.LogLevel >= LogMessageSeverity.Verbose) | |||
{ | |||
UserIsTypingUpdated += (s, e) => RaiseOnLog(LogMessageSeverity.Verbose, LogMessageSource.Client, | |||
$"Updated User (Is Typing): {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}/{e.User?.Name}"); | |||
$"User Updated (Is Typing): {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}/{e.User?.Name}"); | |||
MessageReadRemotely += (s, e) => RaiseOnLog(LogMessageSeverity.Verbose, LogMessageSource.Client, | |||
$"Read Message (Remotely): {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}/{e.Message?.Id}"); | |||
MessageSent += (s, e) => RaiseOnLog(LogMessageSeverity.Verbose, LogMessageSource.Client, | |||
$"Sent Message: {e.Server?.Name ?? "[Private]"}/{e.Channel?.Name}/{e.Message?.Id}"); | |||
UserPresenceUpdated += (s, e) => RaiseOnLog(LogMessageSeverity.Verbose, LogMessageSource.Client, | |||
$"Updated Member (Presence): {e.Server?.Name ?? "[Private]"}/{e.User?.Name}"); | |||
$"User Updated (Presence): {e.Server?.Name ?? "[Private]"}/{e.User?.Name}"); | |||
_api.RestClient.OnRequest += (s, e) => | |||
{ | |||
@@ -140,9 +140,9 @@ namespace Discord | |||
_channels.ItemCreated += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Created Channel {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Id}"); | |||
_channels.ItemDestroyed += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Destroyed Channel {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Id}"); | |||
_channels.Cleared += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Cleared Channels"); | |||
_users.ItemCreated += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Created Member {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Id}"); | |||
_users.ItemDestroyed += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Destroyed Member {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Id}"); | |||
_users.Cleared += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Cleared Members"); | |||
_users.ItemCreated += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Created User {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Id}"); | |||
_users.ItemDestroyed += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Destroyed User {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Id}"); | |||
_users.Cleared += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Cleared Users"); | |||
_messages.ItemCreated += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Created Message {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Channel.Id}/{e.Item.Id}"); | |||
_messages.ItemDestroyed += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Destroyed Message {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Channel.Id}/{e.Item.Id}"); | |||
_messages.ItemRemapped += (s, e) => RaiseOnLog(LogMessageSeverity.Debug, LogMessageSource.Cache, $"Remapped Message {e.Item.Server?.Id ?? "[Private]"}/{e.Item.Channel.Id}/[{e.OldId} -> {e.NewId}]"); | |||
@@ -406,7 +406,7 @@ namespace Discord | |||
if (user != null) | |||
{ | |||
user.Update(data); | |||
RaiseMemberUpdated(user); | |||
RaiseUserUpdated(user); | |||
} | |||
} | |||
break; | |||
@@ -418,6 +418,17 @@ namespace Discord | |||
RaiseUserRemoved(user); | |||
} | |||
break; | |||
case "GUILD_MEMBERS_CHUNK": | |||
{ | |||
var data = e.Payload.ToObject<MembersChunkEvent>(_serializer); | |||
foreach (var memberData in data.Members) | |||
{ | |||
var user = _users.GetOrAdd(memberData.User.Id, memberData.GuildId); | |||
user.Update(memberData); | |||
//RaiseUserAdded(user); | |||
} | |||
} | |||
break; | |||
//Roles | |||
case "GUILD_ROLE_CREATE": | |||
@@ -499,7 +510,7 @@ namespace Discord | |||
} | |||
} | |||
RaiseMessageCreated(msg); | |||
RaiseMessageReceived(msg); | |||
if (Config.AckMessages && !isAuthor) | |||
await _api.AckMessage(data.Id, data.ChannelId).ConfigureAwait(false); | |||
@@ -63,6 +63,6 @@ namespace Discord | |||
_getItem = getItem; | |||
_onCache = onCache; | |||
_onUncache = onUncache; | |||
} | |||
} | |||
} | |||
} |
@@ -26,24 +26,54 @@ namespace Discord | |||
[JsonIgnore] | |||
public User Inviter => _inviter.Value; | |||
private readonly Reference<User> _inviter; | |||
private User _generatedInviter; | |||
/// <summary> Returns the server this invite is to. </summary> | |||
[JsonIgnore] | |||
public Server Server => _server.Value; | |||
private readonly Reference<Server> _server; | |||
private Server _generatedServer; | |||
/// <summary> Returns the channel this invite is to. </summary> | |||
[JsonIgnore] | |||
public Channel Channel => _channel.Value; | |||
private readonly Reference<Channel> _channel; | |||
private Channel _generatedChannel; | |||
internal Invite(DiscordClient client, string code, string xkcdPass, string serverId, string inviterId, string channelId) | |||
: base(client, code) | |||
{ | |||
XkcdCode = xkcdPass; | |||
_server = new Reference<Server>(serverId, x => _client.Servers[x] ?? new Server(client, x)); | |||
_inviter = new Reference<User>(serverId, x => _client.Users[x, _server.Id] ?? new User(client, x, _server.Id)); | |||
_channel = new Reference<Channel>(serverId, x => _client.Channels[x] ?? new Channel(client, x, _server.Id, null)); | |||
_server = new Reference<Server>(serverId, x => | |||
{ | |||
var server = _client.Servers[x]; | |||
if (server == null) | |||
{ | |||
server = _generatedServer = new Server(client, x); | |||
server.Cache(); | |||
} | |||
return server; | |||
}); | |||
_inviter = new Reference<User>(serverId, x => | |||
{ | |||
var inviter = _client.Users[x, _server.Id]; | |||
if (inviter == null) | |||
{ | |||
inviter = _generatedInviter = new User(client, x, _server.Id); | |||
inviter.Cache(); | |||
} | |||
return inviter; | |||
}); | |||
_channel = new Reference<Channel>(serverId, x => | |||
{ | |||
var channel = _client.Channels[x]; | |||
if (channel == null) | |||
{ | |||
channel = _generatedChannel = new Channel(client, x, _server.Id, null); | |||
channel.Cache(); | |||
} | |||
return channel; | |||
}); | |||
} | |||
internal override void LoadReferences() | |||
{ | |||
@@ -54,10 +84,21 @@ namespace Discord | |||
internal override void UnloadReferences() { } | |||
public override string ToString() => XkcdCode ?? Id; | |||
internal void Update(InviteInfo model) | |||
internal void Update(InviteReference model) | |||
{ | |||
if (model.Guild != null && _generatedServer != null) | |||
_generatedServer.Update(model.Guild); | |||
if (model.Inviter != null && _generatedInviter != null) | |||
_generatedInviter.Update(model.Inviter); | |||
if (model.Channel != null && _generatedChannel != null) | |||
_generatedChannel.Update(model.Channel); | |||
} | |||
internal void Update(InviteInfo model) | |||
{ | |||
Update(model as InviteReference); | |||
if (model.IsRevoked != null) | |||
IsRevoked = model.IsRevoked.Value; | |||
if (model.IsTemporary != null) | |||
@@ -68,6 +109,6 @@ namespace Discord | |||
MaxUses = model.MaxUses.Value; | |||
if (model.Uses != null) | |||
Uses = model.Uses.Value; | |||
} | |||
} | |||
} | |||
} |
@@ -55,11 +55,6 @@ namespace Discord | |||
public IEnumerable<Channel> VoiceChannels => _channels.Select(x => x.Value).Where(x => x.Type == ChannelType.Voice); | |||
private ConcurrentDictionary<string, Channel> _channels; | |||
/// <summary> Returns a collection of all invites to this server. </summary> | |||
[JsonIgnore] | |||
public IEnumerable<Invite> Invites => _invites.Values; | |||
private ConcurrentDictionary<string, Invite> _invites; | |||
/// <summary> Returns a collection of all users within this server with their server-specific data. </summary> | |||
[JsonIgnore] | |||
public IEnumerable<User> Members => _members.Select(x => x.Value); | |||
@@ -85,7 +80,6 @@ namespace Discord | |||
//Local Cache | |||
_bans = new ConcurrentDictionary<string, bool>(); | |||
_invites = new ConcurrentDictionary<string, Invite>(); | |||
} | |||
internal override void LoadReferences() | |||
{ | |||
@@ -113,25 +107,26 @@ namespace Discord | |||
roles.Clear(); | |||
//Local Cache | |||
var invites = _invites; | |||
foreach (var invite in invites) | |||
invite.Value.Uncache(); | |||
invites.Clear(); | |||
_bans.Clear(); | |||
_afkChannel.Unload(); | |||
} | |||
internal void Update(GuildInfo model) | |||
internal void Update(GuildReference model) | |||
{ | |||
if (model.Name != null) | |||
Name = model.Name; | |||
} | |||
internal void Update(GuildInfo model) | |||
{ | |||
Update(model as GuildReference); | |||
if (model.AFKTimeout != null) | |||
AFKTimeout = model.AFKTimeout.Value; | |||
if (model.AFKChannelId != null) | |||
if (model.JoinedAt != null) | |||
JoinedAt = model.JoinedAt.Value; | |||
if (model.Name != null) | |||
Name = model.Name; | |||
if (model.OwnerId != null && _ownerId != model.OwnerId) | |||
{ | |||
_ownerId = model.OwnerId; | |||
@@ -212,9 +207,6 @@ namespace Discord | |||
_channels.TryRemove(channel.Id, out channel); | |||
} | |||
internal void AddInvite(Invite invite) => _invites.TryAdd(invite.Id, invite); | |||
internal void RemoveInvite(Invite invite) => _invites.TryRemove(invite.Id, out invite); | |||
internal void AddMember(User user) | |||
{ | |||
if (_members.TryAdd(user.Id, user)) | |||
@@ -24,7 +24,7 @@ namespace Discord | |||
/// <summary> Returns the unique identifier for this user's current avatar. </summary> | |||
public string AvatarId { get; private set; } | |||
/// <summary> Returns the URL to this user's current avatar. </summary> | |||
public string AvatarUrl => API.Endpoints.UserAvatar(Id, AvatarId); | |||
public string AvatarUrl => AvatarId != null ? API.Endpoints.UserAvatar(Id, AvatarId) : null; | |||
/// <summary> Returns the datetime that this user joined this server. </summary> | |||
public DateTime JoinedAt { get; private set; } | |||
@@ -61,7 +61,8 @@ namespace Discord | |||
private readonly Reference<Server> _server; | |||
[JsonIgnore] | |||
public Channel VoiceChannel { get; private set; } | |||
public Channel VoiceChannel => _voiceChannel.Value; | |||
private Reference<Channel> _voiceChannel; | |||
[JsonIgnore] | |||
public IEnumerable<Role> Roles => _roles.Select(x => x.Value); | |||
@@ -130,6 +131,8 @@ namespace Discord | |||
if (Id == _client.CurrentUserId) | |||
x.CurrentUser = null; | |||
}); | |||
_voiceChannel = new Reference<Channel>(x => _client.Channels[x]); | |||
Status = UserStatus.Offline; | |||
_channels = new ConcurrentDictionary<string, Channel>(); | |||
if (serverId != null) | |||
@@ -210,16 +213,16 @@ namespace Discord | |||
SessionId = model.SessionId; | |||
if (model.Token != null) | |||
Token = model.Token; | |||
if (model.ChannelId != null) | |||
VoiceChannel = _client.Channels[model.ChannelId]; | |||
if (model.IsSelfDeafened != null) | |||
IsSelfDeafened = model.IsSelfDeafened.Value; | |||
if (model.IsSelfMuted != null) | |||
IsSelfMuted = model.IsSelfMuted.Value; | |||
if (model.IsServerSuppressed != null) | |||
IsServerSuppressed = model.IsServerSuppressed.Value; | |||
} | |||
_voiceChannel.Id = model.ChannelId; //Can be null | |||
} | |||
private void UpdateRoles(IEnumerable<Role> roles) | |||
{ | |||
if (_server.Id != null) | |||
@@ -27,7 +27,7 @@ namespace Discord.Net.WebSockets | |||
msg.Payload.Token = token; | |||
msg.Payload.Properties["$device"] = "Discord.Net"; | |||
if (_client.Config.UseLargeThreshold) | |||
msg.Payload.LargeThreshold = 50; | |||
msg.Payload.LargeThreshold = 100; | |||
msg.Payload.Compress = true; | |||
QueueMessage(msg); | |||
} | |||
@@ -141,5 +141,11 @@ namespace Discord.Net.WebSockets | |||
leaveVoice.Payload.ServerId = serverId; | |||
QueueMessage(leaveVoice); | |||
} | |||
public void SendGetUsers(string serverId, string query = "", int limit = 0) | |||
{ | |||
var getOfflineUsers = new GetUsersCommand(); | |||
getOfflineUsers.Payload.ServerId = serverId; | |||
QueueMessage(getOfflineUsers); | |||
} | |||
} | |||
} |
@@ -1,5 +1,5 @@ | |||
{ | |||
"version": "0.8.0-beta1", | |||
"version": "0.8.1-beta1", | |||
"description": "An unofficial .Net API wrapper for the Discord client.", | |||
"authors": [ | |||
"RogueException" | |||