@@ -1,11 +1,14 @@ | |||
# Discord.Net v1.0.0-dev | |||
[](https://www.nuget.org/packages/Discord.Net) [](https://ci.appveyor.com/project/foxbot/discord-net/) [](https://discord.gg/0SBTUU1wZTYLhAAW) | |||
[](https://ci.appveyor.com/project/foxbot/discord-net/branch/master) | |||
Discord.Net is an API wrapper for [Discord](http://discordapp.com) written in C#. | |||
An unofficial .Net API Wrapper for the Discord client (http://discordapp.com). | |||
Check out the [documentation](https://discordnet.readthedocs.org/en/latest/) or join the [Discord API Chat](https://discord.gg/0SBTUU1wZTVjAMPx). | |||
Check out the [documentation](http://rtd.discord.foxbot.me/en/docs-dev/index.html) or join the [Discord API Chat](https://discord.gg/0SBTUU1wZTVjAMPx). | |||
## Installing | |||
##### Warning: Some of the documentation is outdated. | |||
It's current being rewritten. Until that's done, feel free to use my [DiscordBot](https://github.com/RogueException/DiscordBot) repo for reference. | |||
### Installation | |||
You can download Discord.Net and its extensions from NuGet: | |||
- [Discord.Net](https://www.nuget.org/packages/Discord.Net/) | |||
- [Discord.Net.Commands](https://www.nuget.org/packages/Discord.Net.Commands/) | |||
@@ -14,9 +17,8 @@ You can download Discord.Net and its extensions from NuGet: | |||
### Compiling | |||
In order to compile Discord.Net, you require at least the following: | |||
- [Visual Studio 15](https://www.visualstudio.com/downloads/download-visual-studio-vs) | |||
- [ASP.Net 5 RC1](https://get.asp.net) | |||
- NuGet 3.3 (available through Visual Studio) | |||
- [Visual Studio 2015](https://www.visualstudio.com/downloads/download-visual-studio-vs) | |||
- [Visual Studio 2015 Update 2](https://www.visualstudio.com/en-us/news/vs2015-update2-vs.aspx) | |||
- [Visual Studio .Net Core Plugin](https://www.microsoft.com/net/core#windows) | |||
- NuGet 3.3+ (available through Visual Studio) | |||
### Known Issues | |||
- .Net Core support is incomplete on non-Windows systems |
@@ -0,0 +1,6 @@ | |||
{ | |||
"projects": [ "src", "test" ], | |||
"sdk": { | |||
"version": "1.0.0-preview1-002702" | |||
} | |||
} |
@@ -10,7 +10,7 @@ namespace Discord.API | |||
[JsonProperty("is_private")] | |||
public bool IsPrivate { get; set; } | |||
[JsonProperty("last_message_id")] | |||
public ulong LastMessageId { get; set; } | |||
public ulong? LastMessageId { get; set; } | |||
//GuildChannel | |||
[JsonProperty("guild_id")] | |||
@@ -23,10 +23,16 @@ namespace Discord.API | |||
public int Position { get; set; } | |||
[JsonProperty("permission_overwrites")] | |||
public Overwrite[] PermissionOverwrites { get; set; } | |||
//TextChannel | |||
[JsonProperty("topic")] | |||
public string Topic { get; set; } | |||
//VoiceChannel | |||
[JsonProperty("bitrate")] | |||
public int Bitrate { get; set; } | |||
[JsonProperty("user_limit")] | |||
public int UserLimit { get; set; } | |||
//DMChannel | |||
[JsonProperty("recipient")] | |||
@@ -0,0 +1,14 @@ | |||
using Newtonsoft.Json; | |||
namespace Discord.API | |||
{ | |||
public class Game | |||
{ | |||
[JsonProperty("name")] | |||
public string Name { get; set; } | |||
[JsonProperty("url")] | |||
public string StreamUrl { get; set; } | |||
[JsonProperty("type")] | |||
public StreamType StreamType { get; set; } | |||
} | |||
} |
@@ -8,9 +8,9 @@ namespace Discord.API | |||
public ulong TargetId { get; set; } | |||
[JsonProperty("type")] | |||
public PermissionTarget TargetType { get; set; } | |||
[JsonProperty("deny")] | |||
public uint Deny { get; set; } | |||
[JsonProperty("allow")] | |||
public uint Allow { get; set; } | |||
[JsonProperty("deny"), Int53] | |||
public ulong Deny { get; set; } | |||
[JsonProperty("allow"), Int53] | |||
public ulong Allow { get; set; } | |||
} | |||
} |
@@ -9,6 +9,6 @@ namespace Discord.API | |||
[JsonProperty("mention_count")] | |||
public int MentionCount { get; set; } | |||
[JsonProperty("last_message_id")] | |||
public ulong LastMentionId { get; set; } | |||
public ulong? LastMessageId { get; set; } | |||
} | |||
} |
@@ -14,8 +14,8 @@ namespace Discord.API | |||
public bool? Hoist { get; set; } | |||
[JsonProperty("position")] | |||
public int? Position { get; set; } | |||
[JsonProperty("permissions")] | |||
public uint? Permissions { get; set; } | |||
[JsonProperty("permissions"), Int53] | |||
public ulong? Permissions { get; set; } | |||
[JsonProperty("managed")] | |||
public bool? Managed { get; set; } | |||
} | |||
@@ -12,7 +12,7 @@ namespace Discord.API | |||
public string Icon { get; set; } | |||
[JsonProperty("owner")] | |||
public bool Owner { get; set; } | |||
[JsonProperty("permissions")] | |||
public uint Permissions { get; set; } | |||
[JsonProperty("permissions"), Int53] | |||
public ulong Permissions { get; set; } | |||
} | |||
} |
@@ -0,0 +1,24 @@ | |||
namespace Discord.API.Gateway | |||
{ | |||
public enum GatewayOpCodes : byte | |||
{ | |||
/// <summary> C←S - Used to send most events. </summary> | |||
Dispatch = 0, | |||
/// <summary> C↔S - Used to keep the connection alive and measure latency. </summary> | |||
Heartbeat = 1, | |||
/// <summary> C→S - Used to associate a connection with a token and specify configuration. </summary> | |||
Identify = 2, | |||
/// <summary> C→S - Used to update client's status and current game id. </summary> | |||
StatusUpdate = 3, | |||
/// <summary> C→S - Used to join a particular voice channel. </summary> | |||
VoiceStateUpdate = 4, | |||
/// <summary> C→S - Used to ensure the server's voice server is alive. Only send this if voice connection fails or suddenly drops. </summary> | |||
VoiceServerPing = 5, | |||
/// <summary> C→S - Used to resume a connection after a redirect occurs. </summary> | |||
Resume = 6, | |||
/// <summary> C←S - Used to notify a client that they must reconnect to another gateway. </summary> | |||
Reconnect = 7, | |||
/// <summary> C→S - Used to request all members that were withheld by large_threshold </summary> | |||
RequestGuildMembers = 8 | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
using Newtonsoft.Json; | |||
namespace Discord.API.Gateway | |||
{ | |||
public class GuildMembersChunkEvent | |||
{ | |||
[JsonProperty("guild_id")] | |||
public ulong GuildId { get; set; } | |||
[JsonProperty("members")] | |||
public GuildMember[] Members { get; set; } | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
using Newtonsoft.Json; | |||
namespace Discord.API.Gateway | |||
{ | |||
public class GuildRoleCreateEvent | |||
{ | |||
[JsonProperty("guild_id")] | |||
public ulong GuildId { get; set; } | |||
[JsonProperty("role")] | |||
public Role Data { get; set; } | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
using Newtonsoft.Json; | |||
namespace Discord.API.Gateway | |||
{ | |||
public class GuildRoleUpdateEvent | |||
{ | |||
[JsonProperty("guild_id")] | |||
public ulong GuildId { get; set; } | |||
[JsonProperty("role")] | |||
public Role Data { get; set; } | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
using Newtonsoft.Json; | |||
using System.Collections.Generic; | |||
namespace Discord.API.Gateway | |||
{ | |||
public class IdentifyParams | |||
{ | |||
[JsonProperty("token")] | |||
public string Token { get; set; } | |||
[JsonProperty("properties")] | |||
public IDictionary<string, string> Properties { get; set; } | |||
[JsonProperty("large_threshold")] | |||
public int LargeThreshold { get; set; } | |||
[JsonProperty("compress")] | |||
public bool UseCompression { get; set; } | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
using Newtonsoft.Json; | |||
namespace Discord.API.Gateway | |||
{ | |||
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 Guild[] 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; } | |||
} | |||
} |
@@ -0,0 +1,14 @@ | |||
using Newtonsoft.Json; | |||
namespace Discord.API.Gateway | |||
{ | |||
public class RequestMembersParams | |||
{ | |||
[JsonProperty("guild_id")] | |||
public ulong[] GuildId { get; set; } | |||
[JsonProperty("query")] | |||
public string Query { get; set; } | |||
[JsonProperty("limit")] | |||
public int Limit { get; set; } | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
using Newtonsoft.Json; | |||
namespace Discord.API.Gateway | |||
{ | |||
public class ResumeParams | |||
{ | |||
[JsonProperty("session_id")] | |||
public string SessionId { get; set; } | |||
[JsonProperty("seq")] | |||
public uint Sequence { get; set; } | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
using Newtonsoft.Json; | |||
namespace Discord.API.Gateway | |||
{ | |||
public class ResumedEvent | |||
{ | |||
[JsonProperty("heartbeat_interval")] | |||
public int HeartbeatInterval { get; set; } | |||
} | |||
} |
@@ -0,0 +1,14 @@ | |||
using Newtonsoft.Json; | |||
namespace Discord.API.Gateway | |||
{ | |||
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; } | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
using Newtonsoft.Json; | |||
namespace Discord.API.Gateway | |||
{ | |||
public class UpdateStatusParams | |||
{ | |||
[JsonProperty("idle_since")] | |||
public long? IdleSince { get; set; } | |||
[JsonProperty("game")] | |||
public Game Game { get; set; } | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
using Newtonsoft.Json; | |||
namespace Discord.API.Gateway | |||
{ | |||
public class UpdateVoiceParams | |||
{ | |||
[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; } | |||
} | |||
} |
@@ -0,0 +1,14 @@ | |||
using Newtonsoft.Json; | |||
namespace Discord.API.Gateway | |||
{ | |||
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; } | |||
} | |||
} |
@@ -0,0 +1,7 @@ | |||
using System; | |||
namespace Discord.API | |||
{ | |||
[AttributeUsage(AttributeTargets.Property)] | |||
public class ImageAttribute : Attribute { } | |||
} |
@@ -0,0 +1,7 @@ | |||
using System; | |||
namespace Discord.API | |||
{ | |||
[AttributeUsage(AttributeTargets.Property)] | |||
public class Int53Attribute : Attribute { } | |||
} |
@@ -1,13 +1,15 @@ | |||
using System; | |||
using System.Diagnostics; | |||
namespace Discord.API | |||
{ | |||
//Based on https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/Nullable.cs | |||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
public struct Optional<T> : IOptional | |||
{ | |||
private readonly T _value; | |||
/// <summary> Gets the value for this paramter, or default(T) if unspecified. </summary> | |||
/// <summary> Gets the value for this paramter. </summary> | |||
public T Value | |||
{ | |||
get | |||
@@ -20,8 +22,6 @@ namespace Discord.API | |||
/// <summary> Returns true if this value has been specified. </summary> | |||
public bool IsSpecified { get; } | |||
object IOptional.Value => _value; | |||
/// <summary> Creates a new Parameter with the provided value. </summary> | |||
public Optional(T value) | |||
{ | |||
@@ -30,7 +30,7 @@ namespace Discord.API | |||
} | |||
public T GetValueOrDefault() => _value; | |||
public T GetValueOrDefault(T defaultValue) => IsSpecified ? _value : default(T); | |||
public T GetValueOrDefault(T defaultValue) => IsSpecified ? _value : defaultValue; | |||
public override bool Equals(object other) | |||
{ | |||
@@ -38,11 +38,14 @@ namespace Discord.API | |||
if (other == null) return false; | |||
return _value.Equals(other); | |||
} | |||
public override int GetHashCode() => IsSpecified ? _value.GetHashCode() : 0; | |||
public override string ToString() => IsSpecified ? _value.ToString() : ""; | |||
public override string ToString() => IsSpecified ? _value?.ToString() : null; | |||
private string DebuggerDisplay => IsSpecified ? _value.ToString() : "<unspecified>"; | |||
public static implicit operator Optional<T>(T value) => new Optional<T>(value); | |||
public static implicit operator T(Optional<T> value) => value.Value; | |||
public static explicit operator T(Optional<T> value) => value.Value; | |||
object IOptional.Value => Value; | |||
} | |||
} |
@@ -1,5 +1,4 @@ | |||
using Discord.Net.Converters; | |||
using Newtonsoft.Json; | |||
using Newtonsoft.Json; | |||
using System.IO; | |||
namespace Discord.API.Rest | |||
@@ -11,7 +10,7 @@ namespace Discord.API.Rest | |||
[JsonProperty("region")] | |||
public string Region { get; set; } | |||
[JsonProperty("icon"), JsonConverter(typeof(ImageConverter))] | |||
[JsonProperty("icon"), Image] | |||
public Optional<Stream> Icon { get; set; } | |||
} | |||
} |
@@ -5,8 +5,8 @@ namespace Discord.API.Rest | |||
public class ModifyChannelPermissionsParams | |||
{ | |||
[JsonProperty("allow")] | |||
public Optional<uint> Allow { get; set; } | |||
public Optional<ulong> Allow { get; set; } | |||
[JsonProperty("deny")] | |||
public Optional<uint> Deny { get; set; } | |||
public Optional<ulong> Deny { get; set; } | |||
} | |||
} |
@@ -14,7 +14,7 @@ namespace Discord.API.Rest | |||
public Optional<string> Password { get; set; } | |||
[JsonProperty("new_password")] | |||
public Optional<string> NewPassword { get; set; } | |||
[JsonProperty("avatar"), JsonConverter(typeof(ImageConverter))] | |||
[JsonProperty("avatar"), Image] | |||
public Optional<Stream> Avatar { get; set; } | |||
} | |||
} |
@@ -5,7 +5,7 @@ namespace Discord.API.Rest | |||
public class ModifyGuildChannelsParams | |||
{ | |||
[JsonProperty("id")] | |||
public Optional<ulong> Id { get; set; } | |||
public ulong Id { get; set; } | |||
[JsonProperty("position")] | |||
public Optional<int> Position { get; set; } | |||
} | |||
@@ -16,11 +16,11 @@ namespace Discord.API.Rest | |||
public Optional<ulong?> AFKChannelId { get; set; } | |||
[JsonProperty("afk_timeout")] | |||
public Optional<int> AFKTimeout { get; set; } | |||
[JsonProperty("icon"), JsonConverter(typeof(ImageConverter))] | |||
[JsonProperty("icon"), Image] | |||
public Optional<Stream> Icon { get; set; } | |||
[JsonProperty("owner_id")] | |||
public Optional<GuildMember> Owner { get; set; } | |||
[JsonProperty("splash"), JsonConverter(typeof(ImageConverter))] | |||
[JsonProperty("splash"), Image] | |||
public Optional<Stream> Splash { get; set; } | |||
} | |||
} |
@@ -7,7 +7,7 @@ namespace Discord.API.Rest | |||
[JsonProperty("name")] | |||
public Optional<string> Name { get; set; } | |||
[JsonProperty("permissions")] | |||
public Optional<uint> Permissions { get; set; } | |||
public Optional<ulong> Permissions { get; set; } | |||
[JsonProperty("position")] | |||
public Optional<int> Position { get; set; } | |||
[JsonProperty("color")] | |||
@@ -5,6 +5,6 @@ namespace Discord.API.Rest | |||
public class ModifyGuildRolesParams : ModifyGuildRoleParams | |||
{ | |||
[JsonProperty("id")] | |||
public Optional<ulong> Id { get; set; } | |||
public ulong Id { get; set; } | |||
} | |||
} |
@@ -6,5 +6,7 @@ namespace Discord.API.Rest | |||
{ | |||
[JsonProperty("bitrate")] | |||
public Optional<int> Bitrate { get; set; } | |||
[JsonProperty("user_limit")] | |||
public Optional<int> UserLimit { get; set; } | |||
} | |||
} |
@@ -0,0 +1,18 @@ | |||
namespace Discord.API.Gateway | |||
{ | |||
public enum VoiceOpCodes : byte | |||
{ | |||
/// <summary> C→S - Used to associate a connection with a token. </summary> | |||
Identify = 0, | |||
/// <summary> C→S - Used to specify configuration. </summary> | |||
SelectProtocol = 1, | |||
/// <summary> C←S - Used to notify that the voice connection was successful and informs the client of available protocols. </summary> | |||
Ready = 2, | |||
/// <summary> C↔S - Used to keep the connection alive and measure latency. </summary> | |||
Heartbeat = 3, | |||
/// <summary> C←S - Used to provide an encryption key to the client. </summary> | |||
SessionDescription = 4, | |||
/// <summary> C↔S - Used to inform that a certain user is speaking. </summary> | |||
Speaking = 5 | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
using Newtonsoft.Json; | |||
namespace Discord.API | |||
{ | |||
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; } | |||
} | |||
} |
@@ -1,7 +0,0 @@ | |||
namespace Discord | |||
{ | |||
public interface IIntegrationAccount : IEntity<string> | |||
{ | |||
string Name { get; } | |||
} | |||
} |
@@ -1,10 +0,0 @@ | |||
namespace Discord | |||
{ | |||
public interface IPublicInvite : IInvite | |||
{ | |||
/// <summary> Gets the name of the the channel this invite is linked to. </summary> | |||
string ChannelName { get; } | |||
/// <summary> Gets the name of the guild this invite is linked to. </summary> | |||
string GuildName { get; } | |||
} | |||
} |
@@ -1,136 +0,0 @@ | |||
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); | |||
/// <summary> Gets a blank ChannelPermissions that grants no permissions. </summary> | |||
public static ChannelPermissions None { get; } = new ChannelPermissions(); | |||
/// <summary> Gets a ChannelPermissions that grants all permissions for a given channelType. </summary> | |||
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)); | |||
} | |||
} | |||
/// <summary> Gets a packed value representing all the permissions in this ChannelPermissions. </summary> | |||
public uint RawValue { get; } | |||
/// <summary> If True, a user may create invites. </summary> | |||
public bool CreateInstantInvite => PermissionUtilities.GetValue(RawValue, ChannelPermission.CreateInstantInvite); | |||
/// <summary> If True, a user may create, delete and modify this channel. </summary> | |||
public bool ManageChannel => PermissionUtilities.GetValue(RawValue, ChannelPermission.ManageChannel); | |||
/// <summary> If True, a user may join channels. </summary> | |||
public bool ReadMessages => PermissionUtilities.GetValue(RawValue, ChannelPermission.ReadMessages); | |||
/// <summary> If True, a user may send messages. </summary> | |||
public bool SendMessages => PermissionUtilities.GetValue(RawValue, ChannelPermission.SendMessages); | |||
/// <summary> If True, a user may send text-to-speech messages. </summary> | |||
public bool SendTTSMessages => PermissionUtilities.GetValue(RawValue, ChannelPermission.SendTTSMessages); | |||
/// <summary> If True, a user may delete messages. </summary> | |||
public bool ManageMessages => PermissionUtilities.GetValue(RawValue, ChannelPermission.ManageMessages); | |||
/// <summary> If True, Discord will auto-embed links sent by this user. </summary> | |||
public bool EmbedLinks => PermissionUtilities.GetValue(RawValue, ChannelPermission.EmbedLinks); | |||
/// <summary> If True, a user may send files. </summary> | |||
public bool AttachFiles => PermissionUtilities.GetValue(RawValue, ChannelPermission.AttachFiles); | |||
/// <summary> If True, a user may read previous messages. </summary> | |||
public bool ReadMessageHistory => PermissionUtilities.GetValue(RawValue, ChannelPermission.ReadMessageHistory); | |||
/// <summary> If True, a user may mention @everyone. </summary> | |||
public bool MentionEveryone => PermissionUtilities.GetValue(RawValue, ChannelPermission.MentionEveryone); | |||
/// <summary> If True, a user may connect to a voice channel. </summary> | |||
public bool Connect => PermissionUtilities.GetValue(RawValue, ChannelPermission.Connect); | |||
/// <summary> If True, a user may speak in a voice channel. </summary> | |||
public bool Speak => PermissionUtilities.GetValue(RawValue, ChannelPermission.Speak); | |||
/// <summary> If True, a user may mute users. </summary> | |||
public bool MuteMembers => PermissionUtilities.GetValue(RawValue, ChannelPermission.MuteMembers); | |||
/// <summary> If True, a user may deafen users. </summary> | |||
public bool DeafenMembers => PermissionUtilities.GetValue(RawValue, ChannelPermission.DeafenMembers); | |||
/// <summary> If True, a user may move other users between voice channels. </summary> | |||
public bool MoveMembers => PermissionUtilities.GetValue(RawValue, ChannelPermission.MoveMembers); | |||
/// <summary> If True, a user may use voice-activity-detection rather than push-to-talk. </summary> | |||
public bool UseVAD => PermissionUtilities.GetValue(RawValue, ChannelPermission.UseVAD); | |||
/// <summary> If True, a user may adjust permissions. This also implictly grants all other permissions. </summary> | |||
public bool ManagePermissions => PermissionUtilities.GetValue(RawValue, ChannelPermission.ManagePermissions); | |||
/// <summary> Creates a new ChannelPermissions with the provided packed value. </summary> | |||
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; | |||
} | |||
/// <summary> Creates a new ChannelPermissions with the provided permissions. </summary> | |||
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) { } | |||
/// <summary> Creates a new ChannelPermissions from this one, changing the provided non-null permissions. </summary> | |||
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); | |||
/// <inheritdoc /> | |||
public override string ToString() | |||
{ | |||
var perms = new List<string>(); | |||
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); | |||
} | |||
} | |||
} |
@@ -1,87 +0,0 @@ | |||
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); | |||
} | |||
} |
@@ -1,8 +0,0 @@ | |||
namespace Discord | |||
{ | |||
public interface IDMUser : IUser | |||
{ | |||
/// <summary> Gets the private channel with this user. </summary> | |||
IDMChannel Channel { get; } | |||
} | |||
} |
@@ -1,20 +0,0 @@ | |||
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; | |||
} | |||
} | |||
} |
@@ -1,13 +0,0 @@ | |||
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<T>(this EventHandler<T> eventHandler, object sender, T eventArgs) | |||
where T : EventArgs | |||
=> eventHandler?.Invoke(sender, eventArgs); | |||
} | |||
} |
@@ -1,64 +0,0 @@ | |||
namespace Discord | |||
{ | |||
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 ITextChannel _: | |||
if (!PermissionUtilities.GetValue(resolvedPermissions, ChannelPermission.ReadMessages)) | |||
resolvedPermissions = 0; //No read permission on a text channel removes all other permissions | |||
break; | |||
case IVoiceChannel _: | |||
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; | |||
} | |||
} | |||
} |
@@ -0,0 +1,475 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using System.Collections.ObjectModel; | |||
using System.Diagnostics; | |||
using System.Threading; | |||
namespace Discord | |||
{ | |||
//Based on https://github.com/dotnet/corefx/blob/master/src/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentDictionary.cs | |||
//Copyright (c) .NET Foundation and Contributors | |||
[DebuggerDisplay("Count = {Count}")] | |||
internal class ConcurrentHashSet<T> : IEnumerable<T> | |||
{ | |||
private sealed class Tables | |||
{ | |||
internal readonly Node[] _buckets; | |||
internal readonly object[] _locks; | |||
internal volatile int[] _countPerLock; | |||
internal Tables(Node[] buckets, object[] locks, int[] countPerLock) | |||
{ | |||
_buckets = buckets; | |||
_locks = locks; | |||
_countPerLock = countPerLock; | |||
} | |||
} | |||
private sealed class Node | |||
{ | |||
internal readonly T _value; | |||
internal volatile Node _next; | |||
internal readonly int _hashcode; | |||
internal Node(T key, int hashcode, Node next) | |||
{ | |||
_value = key; | |||
_next = next; | |||
_hashcode = hashcode; | |||
} | |||
} | |||
private const int DefaultCapacity = 31; | |||
private const int MaxLockNumber = 1024; | |||
private static int GetBucket(int hashcode, int bucketCount) | |||
{ | |||
int bucketNo = (hashcode & 0x7fffffff) % bucketCount; | |||
return bucketNo; | |||
} | |||
private static void GetBucketAndLockNo(int hashcode, out int bucketNo, out int lockNo, int bucketCount, int lockCount) | |||
{ | |||
bucketNo = (hashcode & 0x7fffffff) % bucketCount; | |||
lockNo = bucketNo % lockCount; | |||
} | |||
private static int DefaultConcurrencyLevel => PlatformHelper.ProcessorCount; | |||
private volatile Tables _tables; | |||
private readonly IEqualityComparer<T> _comparer; | |||
private readonly bool _growLockArray; | |||
private int _budget; | |||
public int Count | |||
{ | |||
get | |||
{ | |||
int count = 0; | |||
int acquiredLocks = 0; | |||
try | |||
{ | |||
AcquireAllLocks(ref acquiredLocks); | |||
for (int i = 0; i < _tables._countPerLock.Length; i++) | |||
count += _tables._countPerLock[i]; | |||
} | |||
finally { ReleaseLocks(0, acquiredLocks); } | |||
return count; | |||
} | |||
} | |||
public bool IsEmpty | |||
{ | |||
get | |||
{ | |||
int acquiredLocks = 0; | |||
try | |||
{ | |||
// Acquire all locks | |||
AcquireAllLocks(ref acquiredLocks); | |||
for (int i = 0; i < _tables._countPerLock.Length; i++) | |||
{ | |||
if (_tables._countPerLock[i] != 0) | |||
return false; | |||
} | |||
} | |||
finally { ReleaseLocks(0, acquiredLocks); } | |||
return true; | |||
} | |||
} | |||
public ReadOnlyCollection<T> Values | |||
{ | |||
get | |||
{ | |||
int locksAcquired = 0; | |||
try | |||
{ | |||
AcquireAllLocks(ref locksAcquired); | |||
List<T> values = new List<T>(); | |||
for (int i = 0; i < _tables._buckets.Length; i++) | |||
{ | |||
Node current = _tables._buckets[i]; | |||
while (current != null) | |||
{ | |||
values.Add(current._value); | |||
current = current._next; | |||
} | |||
} | |||
return new ReadOnlyCollection<T>(values); | |||
} | |||
finally { ReleaseLocks(0, locksAcquired); } | |||
} | |||
} | |||
public ConcurrentHashSet() | |||
: this(DefaultConcurrencyLevel, DefaultCapacity, true, EqualityComparer<T>.Default) { } | |||
public ConcurrentHashSet(int concurrencyLevel, int capacity) | |||
: this(concurrencyLevel, capacity, false, EqualityComparer<T>.Default) { } | |||
public ConcurrentHashSet(IEnumerable<T> collection) | |||
: this(collection, EqualityComparer<T>.Default) { } | |||
public ConcurrentHashSet(IEqualityComparer<T> comparer) | |||
: this(DefaultConcurrencyLevel, DefaultCapacity, true, comparer) { } | |||
public ConcurrentHashSet(IEnumerable<T> collection, IEqualityComparer<T> comparer) | |||
: this(comparer) | |||
{ | |||
if (collection == null) throw new ArgumentNullException(nameof(collection)); | |||
InitializeFromCollection(collection); | |||
} | |||
public ConcurrentHashSet(int concurrencyLevel, IEnumerable<T> collection, IEqualityComparer<T> comparer) | |||
: this(concurrencyLevel, DefaultCapacity, false, comparer) | |||
{ | |||
if (collection == null) throw new ArgumentNullException(nameof(collection)); | |||
if (comparer == null) throw new ArgumentNullException(nameof(comparer)); | |||
InitializeFromCollection(collection); | |||
} | |||
public ConcurrentHashSet(int concurrencyLevel, int capacity, IEqualityComparer<T> comparer) | |||
: this(concurrencyLevel, capacity, false, comparer) { } | |||
internal ConcurrentHashSet(int concurrencyLevel, int capacity, bool growLockArray, IEqualityComparer<T> comparer) | |||
{ | |||
if (concurrencyLevel < 1) throw new ArgumentOutOfRangeException(nameof(concurrencyLevel)); | |||
if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity)); | |||
if (comparer == null) throw new ArgumentNullException(nameof(comparer)); | |||
if (capacity < concurrencyLevel) | |||
capacity = concurrencyLevel; | |||
object[] locks = new object[concurrencyLevel]; | |||
for (int i = 0; i < locks.Length; i++) | |||
locks[i] = new object(); | |||
int[] countPerLock = new int[locks.Length]; | |||
Node[] buckets = new Node[capacity]; | |||
_tables = new Tables(buckets, locks, countPerLock); | |||
_comparer = comparer; | |||
_growLockArray = growLockArray; | |||
_budget = buckets.Length / locks.Length; | |||
} | |||
private void InitializeFromCollection(IEnumerable<T> collection) | |||
{ | |||
foreach (var value in collection) | |||
{ | |||
if (value == null) throw new ArgumentNullException("key"); | |||
if (!TryAddInternal(value, _comparer.GetHashCode(value), false)) | |||
throw new ArgumentException(); | |||
} | |||
if (_budget == 0) | |||
_budget = _tables._buckets.Length / _tables._locks.Length; | |||
} | |||
public bool ContainsKey(T value) | |||
{ | |||
if (value == null) throw new ArgumentNullException("key"); | |||
return ContainsKeyInternal(value, _comparer.GetHashCode(value)); | |||
} | |||
private bool ContainsKeyInternal(T value, int hashcode) | |||
{ | |||
Tables tables = _tables; | |||
int bucketNo = GetBucket(hashcode, tables._buckets.Length); | |||
Node n = Volatile.Read(ref tables._buckets[bucketNo]); | |||
while (n != null) | |||
{ | |||
if (hashcode == n._hashcode && _comparer.Equals(n._value, value)) | |||
return true; | |||
n = n._next; | |||
} | |||
return false; | |||
} | |||
public bool TryAdd(T value) | |||
{ | |||
if (value == null) throw new ArgumentNullException("key"); | |||
return TryAddInternal(value, _comparer.GetHashCode(value), true); | |||
} | |||
private bool TryAddInternal(T value, int hashcode, bool acquireLock) | |||
{ | |||
while (true) | |||
{ | |||
int bucketNo, lockNo; | |||
Tables tables = _tables; | |||
GetBucketAndLockNo(hashcode, out bucketNo, out lockNo, tables._buckets.Length, tables._locks.Length); | |||
bool resizeDesired = false; | |||
bool lockTaken = false; | |||
try | |||
{ | |||
if (acquireLock) | |||
Monitor.Enter(tables._locks[lockNo], ref lockTaken); | |||
if (tables != _tables) | |||
continue; | |||
Node prev = null; | |||
for (Node node = tables._buckets[bucketNo]; node != null; node = node._next) | |||
{ | |||
if (hashcode == node._hashcode && _comparer.Equals(node._value, value)) | |||
return false; | |||
prev = node; | |||
} | |||
Volatile.Write(ref tables._buckets[bucketNo], new Node(value, hashcode, tables._buckets[bucketNo])); | |||
checked { tables._countPerLock[lockNo]++; } | |||
if (tables._countPerLock[lockNo] > _budget) | |||
resizeDesired = true; | |||
} | |||
finally | |||
{ | |||
if (lockTaken) | |||
Monitor.Exit(tables._locks[lockNo]); | |||
} | |||
if (resizeDesired) | |||
GrowTable(tables); | |||
return true; | |||
} | |||
} | |||
public bool TryRemove(T value) | |||
{ | |||
if (value == null) throw new ArgumentNullException("key"); | |||
return TryRemoveInternal(value); | |||
} | |||
private bool TryRemoveInternal(T value) | |||
{ | |||
int hashcode = _comparer.GetHashCode(value); | |||
while (true) | |||
{ | |||
Tables tables = _tables; | |||
int bucketNo, lockNo; | |||
GetBucketAndLockNo(hashcode, out bucketNo, out lockNo, tables._buckets.Length, tables._locks.Length); | |||
lock (tables._locks[lockNo]) | |||
{ | |||
if (tables != _tables) | |||
continue; | |||
Node prev = null; | |||
for (Node curr = tables._buckets[bucketNo]; curr != null; curr = curr._next) | |||
{ | |||
if (hashcode == curr._hashcode && _comparer.Equals(curr._value, value)) | |||
{ | |||
if (prev == null) | |||
Volatile.Write(ref tables._buckets[bucketNo], curr._next); | |||
else | |||
prev._next = curr._next; | |||
value = curr._value; | |||
tables._countPerLock[lockNo]--; | |||
return true; | |||
} | |||
prev = curr; | |||
} | |||
} | |||
value = default(T); | |||
return false; | |||
} | |||
} | |||
public void Clear() | |||
{ | |||
int locksAcquired = 0; | |||
try | |||
{ | |||
AcquireAllLocks(ref locksAcquired); | |||
Tables newTables = new Tables(new Node[DefaultCapacity], _tables._locks, new int[_tables._countPerLock.Length]); | |||
_tables = newTables; | |||
_budget = Math.Max(1, newTables._buckets.Length / newTables._locks.Length); | |||
} | |||
finally | |||
{ | |||
ReleaseLocks(0, locksAcquired); | |||
} | |||
} | |||
public IEnumerator<T> GetEnumerator() | |||
{ | |||
Node[] buckets = _tables._buckets; | |||
for (int i = 0; i < buckets.Length; i++) | |||
{ | |||
Node current = Volatile.Read(ref buckets[i]); | |||
while (current != null) | |||
{ | |||
yield return current._value; | |||
current = current._next; | |||
} | |||
} | |||
} | |||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |||
private void GrowTable(Tables tables) | |||
{ | |||
const int MaxArrayLength = 0X7FEFFFFF; | |||
int locksAcquired = 0; | |||
try | |||
{ | |||
AcquireLocks(0, 1, ref locksAcquired); | |||
if (tables != _tables) | |||
return; | |||
long approxCount = 0; | |||
for (int i = 0; i < tables._countPerLock.Length; i++) | |||
approxCount += tables._countPerLock[i]; | |||
if (approxCount < tables._buckets.Length / 4) | |||
{ | |||
_budget = 2 * _budget; | |||
if (_budget < 0) | |||
_budget = int.MaxValue; | |||
return; | |||
} | |||
int newLength = 0; | |||
bool maximizeTableSize = false; | |||
try | |||
{ | |||
checked | |||
{ | |||
newLength = tables._buckets.Length * 2 + 1; | |||
while (newLength % 3 == 0 || newLength % 5 == 0 || newLength % 7 == 0) | |||
newLength += 2; | |||
if (newLength > MaxArrayLength) | |||
maximizeTableSize = true; | |||
} | |||
} | |||
catch (OverflowException) | |||
{ | |||
maximizeTableSize = true; | |||
} | |||
if (maximizeTableSize) | |||
{ | |||
newLength = MaxArrayLength; | |||
_budget = int.MaxValue; | |||
} | |||
AcquireLocks(1, tables._locks.Length, ref locksAcquired); | |||
object[] newLocks = tables._locks; | |||
if (_growLockArray && tables._locks.Length < MaxLockNumber) | |||
{ | |||
newLocks = new object[tables._locks.Length * 2]; | |||
Array.Copy(tables._locks, 0, newLocks, 0, tables._locks.Length); | |||
for (int i = tables._locks.Length; i < newLocks.Length; i++) | |||
newLocks[i] = new object(); | |||
} | |||
Node[] newBuckets = new Node[newLength]; | |||
int[] newCountPerLock = new int[newLocks.Length]; | |||
for (int i = 0; i < tables._buckets.Length; i++) | |||
{ | |||
Node current = tables._buckets[i]; | |||
while (current != null) | |||
{ | |||
Node next = current._next; | |||
int newBucketNo, newLockNo; | |||
GetBucketAndLockNo(current._hashcode, out newBucketNo, out newLockNo, newBuckets.Length, newLocks.Length); | |||
newBuckets[newBucketNo] = new Node(current._value, current._hashcode, newBuckets[newBucketNo]); | |||
checked { newCountPerLock[newLockNo]++; } | |||
current = next; | |||
} | |||
} | |||
_budget = Math.Max(1, newBuckets.Length / newLocks.Length); | |||
_tables = new Tables(newBuckets, newLocks, newCountPerLock); | |||
} | |||
finally { ReleaseLocks(0, locksAcquired); } | |||
} | |||
private void AcquireAllLocks(ref int locksAcquired) | |||
{ | |||
AcquireLocks(0, 1, ref locksAcquired); | |||
AcquireLocks(1, _tables._locks.Length, ref locksAcquired); | |||
} | |||
private void AcquireLocks(int fromInclusive, int toExclusive, ref int locksAcquired) | |||
{ | |||
object[] locks = _tables._locks; | |||
for (int i = fromInclusive; i < toExclusive; i++) | |||
{ | |||
bool lockTaken = false; | |||
try | |||
{ | |||
Monitor.Enter(locks[i], ref lockTaken); | |||
} | |||
finally | |||
{ | |||
if (lockTaken) | |||
locksAcquired++; | |||
} | |||
} | |||
} | |||
private void ReleaseLocks(int fromInclusive, int toExclusive) | |||
{ | |||
for (int i = fromInclusive; i < toExclusive; i++) | |||
Monitor.Exit(_tables._locks[i]); | |||
} | |||
} | |||
//https://github.com/dotnet/corefx/blob/d0dc5fc099946adc1035b34a8b1f6042eddb0c75/src/System.Threading.Tasks.Parallel/src/System/Threading/PlatformHelper.cs | |||
//Copyright (c) .NET Foundation and Contributors | |||
internal static class PlatformHelper | |||
{ | |||
private const int PROCESSOR_COUNT_REFRESH_INTERVAL_MS = 30000; | |||
private static volatile int s_processorCount; | |||
private static volatile int s_lastProcessorCountRefreshTicks; | |||
internal static int ProcessorCount | |||
{ | |||
get | |||
{ | |||
int now = Environment.TickCount; | |||
if (s_processorCount == 0 || (now - s_lastProcessorCountRefreshTicks) >= PROCESSOR_COUNT_REFRESH_INTERVAL_MS) | |||
{ | |||
s_processorCount = Environment.ProcessorCount; | |||
s_lastProcessorCountRefreshTicks = now; | |||
} | |||
return s_processorCount; | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
namespace Discord | |||
{ | |||
public enum ConnectionState : byte | |||
{ | |||
Disconnected, | |||
Connecting, | |||
Connected, | |||
Disconnecting | |||
} | |||
} |
@@ -2,9 +2,10 @@ | |||
namespace Discord | |||
{ | |||
internal static class DateTimeHelper | |||
internal static class DateTimeUtils | |||
{ | |||
private const ulong EpochTicks = 621355968000000000UL; | |||
private const ulong DiscordEpochMillis = 1420070400000UL; | |||
public static DateTime FromEpochMilliseconds(ulong value) | |||
=> new DateTime((long)(value * TimeSpan.TicksPerMillisecond + EpochTicks), DateTimeKind.Utc); | |||
@@ -12,6 +13,6 @@ namespace Discord | |||
=> new DateTime((long)(value * TimeSpan.TicksPerSecond + EpochTicks), DateTimeKind.Utc); | |||
public static DateTime FromSnowflake(ulong value) | |||
=> FromEpochMilliseconds((value >> 22) + 1420070400000UL); | |||
=> FromEpochMilliseconds((value >> 22) + DiscordEpochMillis); | |||
} | |||
} |
@@ -1,223 +0,0 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<Project ToolsVersion="15.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>{18F6FE23-73F6-4CA6-BBD9-F0139DC3EE90}</ProjectGuid> | |||
<OutputType>Library</OutputType> | |||
<AppDesignerFolder>Properties</AppDesignerFolder> | |||
<RootNamespace>Discord</RootNamespace> | |||
<AssemblyName>Discord.Net</AssemblyName> | |||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> | |||
<FileAlignment>512</FileAlignment> | |||
<TargetFrameworkProfile /> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | |||
<DebugSymbols>true</DebugSymbols> | |||
<DebugType>full</DebugType> | |||
<Optimize>false</Optimize> | |||
<OutputPath>bin\Debug\</OutputPath> | |||
<DefineConstants>TRACE;DEBUG;__DEMO__,__DEMO_EXPERIMENTAL__</DefineConstants> | |||
<ErrorReport>prompt</ErrorReport> | |||
<WarningLevel>4</WarningLevel> | |||
</PropertyGroup> | |||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||
<DebugType>pdbonly</DebugType> | |||
<Optimize>true</Optimize> | |||
<OutputPath>bin\Release\</OutputPath> | |||
<DefineConstants>TRACE</DefineConstants> | |||
<ErrorReport>prompt</ErrorReport> | |||
<WarningLevel>4</WarningLevel> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<Reference Include="System" /> | |||
<Reference Include="System.Core" /> | |||
<Reference Include="System.Xml.Linq" /> | |||
<Reference Include="System.Data.DataSetExtensions" /> | |||
<Reference Include="Microsoft.CSharp" /> | |||
<Reference Include="System.Data" /> | |||
<Reference Include="System.Net.Http" /> | |||
<Reference Include="System.Xml" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Compile Include="API\CDN.cs" /> | |||
<Compile Include="API\Common\Attachment.cs" /> | |||
<Compile Include="API\Common\Channel.cs" /> | |||
<Compile Include="API\Common\Connection.cs" /> | |||
<Compile Include="API\Common\Embed.cs" /> | |||
<Compile Include="API\Common\EmbedProvider.cs" /> | |||
<Compile Include="API\Common\EmbedThumbnail.cs" /> | |||
<Compile Include="API\Common\Emoji.cs" /> | |||
<Compile Include="API\Common\Guild.cs" /> | |||
<Compile Include="API\Common\GuildEmbed.cs" /> | |||
<Compile Include="API\Common\GuildMember.cs" /> | |||
<Compile Include="API\Common\Integration.cs" /> | |||
<Compile Include="API\Common\IntegrationAccount.cs" /> | |||
<Compile Include="API\Common\Invite.cs" /> | |||
<Compile Include="API\Common\InviteChannel.cs" /> | |||
<Compile Include="API\Common\InviteGuild.cs" /> | |||
<Compile Include="API\Common\InviteMetadata.cs" /> | |||
<Compile Include="API\Common\Message.cs" /> | |||
<Compile Include="API\Common\Overwrite.cs" /> | |||
<Compile Include="API\Common\ReadState.cs" /> | |||
<Compile Include="API\Common\Role.cs" /> | |||
<Compile Include="API\Common\User.cs" /> | |||
<Compile Include="API\Common\UserGuild.cs" /> | |||
<Compile Include="API\Common\VoiceRegion.cs" /> | |||
<Compile Include="API\Common\VoiceState.cs" /> | |||
<Compile Include="API\IOptional.cs" /> | |||
<Compile Include="API\Optional.cs" /> | |||
<Compile Include="API\Rest\DeleteMessagesParam.cs" /> | |||
<Compile Include="API\Rest\GetGuildMembersParams.cs" /> | |||
<Compile Include="API\Rest\LoginParams.cs" /> | |||
<Compile Include="API\Rest\LoginResponse.cs" /> | |||
<Compile Include="API\Rest\ModifyCurrentUserNickParams.cs" /> | |||
<Compile Include="API\Rest\UploadFileParams.cs" /> | |||
<Compile Include="API\Rest\GuildPruneParams.cs" /> | |||
<Compile Include="API\Rest\CreateChannelInviteParams.cs" /> | |||
<Compile Include="API\Rest\CreateDMChannelParams.cs" /> | |||
<Compile Include="API\Rest\CreateGuildParams.cs" /> | |||
<Compile Include="API\Rest\CreateGuildBanParams.cs" /> | |||
<Compile Include="API\Rest\CreateGuildChannelParams.cs" /> | |||
<Compile Include="API\Rest\CreateGuildIntegrationParams.cs" /> | |||
<Compile Include="API\Rest\CreateMessageParams.cs" /> | |||
<Compile Include="API\Rest\GetChannelMessagesParams.cs" /> | |||
<Compile Include="API\Rest\GetGatewayResponse.cs" /> | |||
<Compile Include="API\Rest\GetGuildPruneCountResponse.cs" /> | |||
<Compile Include="API\Rest\ModifyChannelPermissionsParams.cs" /> | |||
<Compile Include="API\Rest\ModifyCurrentUserParams.cs" /> | |||
<Compile Include="API\Rest\ModifyGuildChannelsParams.cs" /> | |||
<Compile Include="API\Rest\ModifyGuildParams.cs" /> | |||
<Compile Include="API\Rest\ModifyGuildChannelParams.cs" /> | |||
<Compile Include="API\Rest\ModifyGuildEmbedParams.cs" /> | |||
<Compile Include="API\Rest\ModifyGuildIntegrationParams.cs" /> | |||
<Compile Include="API\Rest\ModifyGuildMemberParams.cs" /> | |||
<Compile Include="API\Rest\ModifyGuildRolesParams.cs" /> | |||
<Compile Include="API\Rest\ModifyGuildRoleParams.cs" /> | |||
<Compile Include="API\Rest\ModifyMessageParams.cs" /> | |||
<Compile Include="API\Rest\ModifyTextChannelParams.cs" /> | |||
<Compile Include="API\Rest\ModifyVoiceChannelParams.cs" /> | |||
<Compile Include="DiscordConfig.cs" /> | |||
<Compile Include="API\DiscordRawClient.cs" /> | |||
<Compile Include="Net\Converters\OptionalContractResolver.cs" /> | |||
<Compile Include="Net\Converters\OptionalConverter.cs" /> | |||
<Compile Include="Net\RateLimitException.cs" /> | |||
<Compile Include="Net\Rest\RequestQueue\BucketGroup.cs" /> | |||
<Compile Include="Net\Rest\RequestQueue\GlobalBucket.cs" /> | |||
<Compile Include="Net\Rest\RequestQueue\GuildBucket.cs" /> | |||
<Compile Include="Net\Rest\RequestQueue\RequestQueue.cs" /> | |||
<Compile Include="Net\Rest\RequestQueue\RequestQueueBucket.cs" /> | |||
<Compile Include="Net\Rest\RequestQueue\RestRequest.cs" /> | |||
<Compile Include="Rest\DiscordClient.cs" /> | |||
<Compile Include="Common\Entities\Guilds\IGuildEmbed.cs" /> | |||
<Compile Include="Common\Entities\Guilds\IIntegrationAccount.cs" /> | |||
<Compile Include="Common\Entities\Users\IConnection.cs" /> | |||
<Compile Include="Common\Entities\Guilds\IGuildIntegration.cs" /> | |||
<Compile Include="Common\Entities\Invites\IPublicInvite.cs" /> | |||
<Compile Include="Common\Entities\Messages\Attachment.cs" /> | |||
<Compile Include="Common\Entities\Channels\IChannel.cs" /> | |||
<Compile Include="Common\Entities\Channels\IDMChannel.cs" /> | |||
<Compile Include="Common\Entities\Channels\IGuildChannel.cs" /> | |||
<Compile Include="Common\Entities\Channels\IMessageChannel.cs" /> | |||
<Compile Include="Common\Entities\Channels\ITextChannel.cs" /> | |||
<Compile Include="Common\Entities\Channels\IVoiceChannel.cs" /> | |||
<Compile Include="Common\Entities\Channels\ChannelType.cs" /> | |||
<Compile Include="Common\Entities\Roles\Color.cs" /> | |||
<Compile Include="Common\Entities\Messages\Direction.cs" /> | |||
<Compile Include="Common\Entities\Messages\Embed.cs" /> | |||
<Compile Include="Common\Entities\Messages\EmbedProvider.cs" /> | |||
<Compile Include="Common\Entities\Messages\EmbedThumbnail.cs" /> | |||
<Compile Include="Common\Entities\Guilds\Emoji.cs" /> | |||
<Compile Include="Common\Entities\Guilds\IUserGuild.cs" /> | |||
<Compile Include="Common\Entities\IDeletable.cs" /> | |||
<Compile Include="Common\Entities\IEntity.cs" /> | |||
<Compile Include="Common\Entities\Guilds\IGuild.cs" /> | |||
<Compile Include="Common\Entities\IMentionable.cs" /> | |||
<Compile Include="Common\Entities\Messages\IMessage.cs" /> | |||
<Compile Include="Common\Entities\Invites\IGuildInvite.cs" /> | |||
<Compile Include="Common\Entities\Invites\IInvite.cs" /> | |||
<Compile Include="Common\Entities\Roles\IRole.cs" /> | |||
<Compile Include="Common\Entities\ISnowflakeEntity.cs" /> | |||
<Compile Include="Common\Entities\IUpdateable.cs" /> | |||
<Compile Include="Common\Entities\Guilds\IVoiceRegion.cs" /> | |||
<Compile Include="Common\Entities\Permissions\ChannelPermission.cs" /> | |||
<Compile Include="Common\Entities\Permissions\GuildPermission.cs" /> | |||
<Compile Include="Common\Entities\Permissions\ChannelPermissions.cs" /> | |||
<Compile Include="Common\Entities\Permissions\GuildPermissions.cs" /> | |||
<Compile Include="Common\Entities\Permissions\Overwrite.cs" /> | |||
<Compile Include="Common\Entities\Permissions\OverwritePermissions.cs" /> | |||
<Compile Include="Common\Entities\Permissions\PermissionUtilities.cs" /> | |||
<Compile Include="Common\Entities\Permissions\PermissionTarget.cs" /> | |||
<Compile Include="Common\Entities\Permissions\PermValue.cs" /> | |||
<Compile Include="Common\Entities\Users\UserStatus.cs" /> | |||
<Compile Include="Common\Entities\Users\IDMUser.cs" /> | |||
<Compile Include="Common\Entities\Users\IGuildUser.cs" /> | |||
<Compile Include="Common\Entities\Users\ISelfUser.cs" /> | |||
<Compile Include="Common\Entities\Users\IUser.cs" /> | |||
<Compile Include="Rest\Entities\Guilds\Guild.cs" /> | |||
<Compile Include="Rest\Entities\Channels\GuildChannel.cs" /> | |||
<Compile Include="Rest\Entities\Channels\TextChannel.cs" /> | |||
<Compile Include="Rest\Entities\Channels\VoiceChannel.cs" /> | |||
<Compile Include="Rest\Entities\Guilds\GuildEmbed.cs" /> | |||
<Compile Include="Rest\Entities\Guilds\GuildIntegration.cs" /> | |||
<Compile Include="Rest\Entities\Guilds\IntegrationAccount.cs" /> | |||
<Compile Include="Rest\Entities\Users\Connection.cs" /> | |||
<Compile Include="Common\Helpers\PermissionHelper.cs" /> | |||
<Compile Include="Rest\Entities\Invites\GuildInvite.cs" /> | |||
<Compile Include="Rest\Entities\Invites\Invite.cs" /> | |||
<Compile Include="Rest\Entities\Invites\PublicInvite.cs" /> | |||
<Compile Include="Rest\Entities\Message.cs" /> | |||
<Compile Include="Rest\Entities\Role.cs" /> | |||
<Compile Include="Rest\Entities\Guilds\UserGuild.cs" /> | |||
<Compile Include="Rest\Entities\Users\DMUser.cs" /> | |||
<Compile Include="Rest\Entities\Users\GuildUser.cs" /> | |||
<Compile Include="Rest\Entities\Users\PublicUser.cs" /> | |||
<Compile Include="Rest\Entities\Guilds\VoiceRegion.cs" /> | |||
<Compile Include="Common\Events\LogMessageEventArgs.cs" /> | |||
<Compile Include="Common\Events\SentRequestEventArgs.cs" /> | |||
<Compile Include="Common\Helpers\DateTimeHelper.cs" /> | |||
<Compile Include="Common\Helpers\EventExtensions.cs" /> | |||
<Compile Include="Common\Helpers\MentionHelper.cs" /> | |||
<Compile Include="IDiscordClient.cs" /> | |||
<Compile Include="Logging\ILogger.cs" /> | |||
<Compile Include="Logging\Logger.cs" /> | |||
<Compile Include="Logging\LogManager.cs" /> | |||
<Compile Include="LogSeverity.cs" /> | |||
<Compile Include="Net\Converters\ChannelTypeConverter.cs" /> | |||
<Compile Include="Net\Converters\ImageConverter.cs" /> | |||
<Compile Include="Net\Converters\NullableUInt64Converter.cs" /> | |||
<Compile Include="Net\Converters\PermissionTargetConverter.cs" /> | |||
<Compile Include="Net\Converters\StringEntityConverter.cs" /> | |||
<Compile Include="Net\Converters\UInt64ArrayConverter.cs" /> | |||
<Compile Include="Net\Converters\UInt64Converter.cs" /> | |||
<Compile Include="Net\Converters\UInt64EntityConverter.cs" /> | |||
<Compile Include="Net\Converters\UserStatusConverter.cs" /> | |||
<Compile Include="Net\HttpException.cs" /> | |||
<Compile Include="Net\Rest\DefaultRestClient.cs" /> | |||
<Compile Include="Net\Rest\RequestQueue\IRequestQueue.cs" /> | |||
<Compile Include="Net\Rest\IRestClient.cs" /> | |||
<Compile Include="Net\Rest\MultipartFile.cs" /> | |||
<Compile Include="Net\Rest\RestClientProvider.cs" /> | |||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||
<Compile Include="Rest\Entities\Channels\DMChannel.cs" /> | |||
<Compile Include="Rest\Entities\Users\SelfUser.cs" /> | |||
<Compile Include="Rest\Entities\Users\User.cs" /> | |||
<Compile Include="TokenType.cs" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Include="Common\Entities\Users\IVoiceState.cs.old" /> | |||
<None Include="project.json" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Folder Include="Net\WebSockets\" /> | |||
</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,19 @@ | |||
<?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)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" /> | |||
<PropertyGroup Label="Globals"> | |||
<ProjectGuid>91e9e7bd-75c9-4e98-84aa-2c271922e5c2</ProjectGuid> | |||
<RootNamespace>Discord</RootNamespace> | |||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath> | |||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath> | |||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion> | |||
</PropertyGroup> | |||
<PropertyGroup> | |||
<SchemaVersion>2.0</SchemaVersion> | |||
</PropertyGroup> | |||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" /> | |||
</Project> |
@@ -3,12 +3,15 @@ using System.Reflection; | |||
namespace Discord | |||
{ | |||
//TODO: Add socket config items in their own class | |||
public class DiscordConfig | |||
{ | |||
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 int GatewayAPIVersion = 3; | |||
public const int GatewayAPIVersion = 3; //TODO: Upgrade to 4 | |||
public const string GatewayEncoding = "json"; | |||
public const string ClientAPIUrl = "https://discordapp.com/api/"; | |||
public const string CDNUrl = "https://cdn.discordapp.com/"; | |||
@@ -26,6 +29,6 @@ namespace Discord | |||
public LogSeverity LogLevel { get; set; } = LogSeverity.Info; | |||
/// <summary> Gets or sets the provider used to generate new REST connections. </summary> | |||
public RestClientProvider RestClientProvider { get; set; } = (url, ct) => new DefaultRestClient(url, ct); | |||
public RestClientProvider RestClientProvider { get; set; } = url => new DefaultRestClient(url); | |||
} | |||
} |
@@ -7,6 +7,8 @@ namespace Discord | |||
{ | |||
/// <summary> Gets a collection of all users in this channel. </summary> | |||
Task<IEnumerable<IUser>> GetUsers(); | |||
/// <summary> Gets a paginated collection of all users in this channel. </summary> | |||
Task<IEnumerable<IUser>> GetUsers(int limit, int offset = 0); | |||
/// <summary> Gets a user in this channel with the provided id.</summary> | |||
Task<IUser> GetUser(ulong id); | |||
} |
@@ -5,7 +5,7 @@ namespace Discord | |||
public interface IDMChannel : IMessageChannel, IUpdateable | |||
{ | |||
/// <summary> Gets the recipient of all messages in this channel. </summary> | |||
IDMUser Recipient { get; } | |||
IUser Recipient { get; } | |||
/// <summary> Closes this private channel, removing it from your channel list. </summary> | |||
Task Close(); |
@@ -20,9 +20,9 @@ namespace Discord | |||
/// <param name="maxUses"> The max amount of times this invite may be used. Set to null to have unlimited uses. </param> | |||
/// <param name="isTemporary"> If true, a user accepting this invite will be kicked from the guild after closing their client. </param> | |||
/// <param name="withXkcd"> If true, creates a human-readable link. Not supported if maxAge is set to null. </param> | |||
Task<IGuildInvite> CreateInvite(int? maxAge = 1800, int? maxUses = default(int?), bool isTemporary = false, bool withXkcd = false); | |||
Task<IInviteMetadata> CreateInvite(int? maxAge = 1800, int? maxUses = default(int?), bool isTemporary = false, bool withXkcd = false); | |||
/// <summary> Returns a collection of all invites to this channel. </summary> | |||
Task<IEnumerable<IGuildInvite>> GetInvites(); | |||
Task<IEnumerable<IInviteMetadata>> GetInvites(); | |||
/// <summary> Gets a collection of permission overwrites for this channel. </summary> | |||
IReadOnlyDictionary<ulong, Overwrite> PermissionOverwrites { get; } |
@@ -6,8 +6,12 @@ namespace Discord | |||
{ | |||
public interface IMessageChannel : IChannel | |||
{ | |||
/// <summary> Gets the message in this message channel with the given id, or null if none was found. </summary> | |||
Task<IMessage> GetMessage(ulong id); | |||
/// <summary> Gets all messages in this channel's cache. </summary> | |||
IEnumerable<IMessage> CachedMessages { get; } | |||
/// <summary> Gets the message from this channel's cache with the given id, or null if none was found. </summary> | |||
Task<IMessage> GetCachedMessage(ulong id); | |||
/// <summary> Gets the last N messages from this message channel. </summary> | |||
Task<IEnumerable<IMessage>> GetMessages(int limit = DiscordConfig.MaxMessagesPerBatch); | |||
/// <summary> Gets a collection of messages in this channel. </summary> |
@@ -8,6 +8,8 @@ namespace Discord | |||
{ | |||
/// <summary> Gets the bitrate, in bits per second, clients in this voice channel are requested to use. </summary> | |||
int Bitrate { get; } | |||
/// <summary> Gets the max amount of users allowed to be connected to this channel at one time. A value of 0 represents no limit. </summary> | |||
int UserLimit { get; } | |||
/// <summary> Modifies this voice channel. </summary> | |||
Task Modify(Action<ModifyVoiceChannelParams> func); |
@@ -70,13 +70,13 @@ namespace Discord | |||
Task<IVoiceChannel> CreateVoiceChannel(string name); | |||
/// <summary> Gets a collection of all invites to this guild. </summary> | |||
Task<IEnumerable<IGuildInvite>> GetInvites(); | |||
Task<IEnumerable<IInviteMetadata>> GetInvites(); | |||
/// <summary> Creates a new invite to this guild. </summary> | |||
/// <param name="maxAge"> The time (in seconds) until the invite expires. Set to null to never expire. </param> | |||
/// <param name="maxUses"> The max amount of times this invite may be used. Set to null to have unlimited uses. </param> | |||
/// <param name="isTemporary"> If true, a user accepting this invite will be kicked from the guild after closing their client. </param> | |||
/// <param name="withXkcd"> If true, creates a human-readable link. Not supported if maxAge is set to null. </param> | |||
Task<IGuildInvite> CreateInvite(int? maxAge = 1800, int? maxUses = default(int?), bool isTemporary = false, bool withXkcd = false); | |||
Task<IInviteMetadata> CreateInvite(int? maxAge = 1800, int? maxUses = default(int?), bool isTemporary = false, bool withXkcd = false); | |||
/// <summary> Gets a collection of all roles in this guild. </summary> | |||
Task<IEnumerable<IRole>> GetRoles(); |
@@ -12,10 +12,10 @@ namespace Discord | |||
ulong ExpireBehavior { get; } | |||
ulong ExpireGracePeriod { get; } | |||
DateTime SyncedAt { get; } | |||
IntegrationAccount Account { get; } | |||
IGuild Guild { get; } | |||
IUser User { get; } | |||
IRole Role { get; } | |||
IIntegrationAccount Account { get; } | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
using System.Diagnostics; | |||
namespace Discord | |||
{ | |||
[DebuggerDisplay("{DebuggerDisplay,nq}")] | |||
public struct IntegrationAccount | |||
{ | |||
/// <inheritdoc /> | |||
public string Id { get; } | |||
/// <inheritdoc /> | |||
public string Name { get; private set; } | |||
public override string ToString() => Name; | |||
private string DebuggerDisplay => $"{Name} ({Id})"; | |||
} | |||
} |
@@ -1,7 +1,9 @@ | |||
using Model = Discord.API.VoiceRegion; | |||
using System.Diagnostics; | |||
using Model = Discord.API.VoiceRegion; | |||
namespace Discord.Rest | |||
namespace Discord | |||
{ | |||
[DebuggerDisplay("{DebuggerDisplay,nq}")] | |||
public class VoiceRegion : IVoiceRegion | |||
{ | |||
/// <inheritdoc /> | |||
@@ -27,6 +29,7 @@ namespace Discord.Rest | |||
SamplePort = model.SamplePort; | |||
} | |||
public override string ToString() => $"{Name ?? Id.ToString()}"; | |||
public override string ToString() => Name; | |||
private string DebuggerDisplay => $"{Name} ({Id}{(IsVip ? ", VIP" : "")}{(IsOptimal ? ", Optimal" : "")})"; | |||
} | |||
} |
@@ -2,7 +2,7 @@ | |||
namespace Discord | |||
{ | |||
public interface IInvite : IEntity<string> | |||
public interface IInvite : IEntity<string>, IDeletable | |||
{ | |||
/// <summary> Gets the unique identifier for this invite. </summary> | |||
string Code { get; } |
@@ -1,6 +1,6 @@ | |||
namespace Discord | |||
{ | |||
public interface IGuildInvite : IDeletable, IInvite | |||
public interface IInviteMetadata : IInvite | |||
{ | |||
/// <summary> Returns true if this invite was revoked. </summary> | |||
bool IsRevoked { get; } | |||
@@ -12,8 +12,5 @@ | |||
int? MaxUses { get; } | |||
/// <summary> Gets the amount of times this invite has been used. </summary> | |||
int Uses { get; } | |||
/// <summary> Gets the guild this invite is linked to. </summary> | |||
IGuild Guild { get; } | |||
} | |||
} |
@@ -0,0 +1,65 @@ | |||
using System.Diagnostics; | |||
using System.Threading.Tasks; | |||
using Model = Discord.API.Invite; | |||
namespace Discord | |||
{ | |||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
public class Invite : IInvite | |||
{ | |||
/// <inheritdoc /> | |||
public string Code { get; } | |||
internal IDiscordClient Discord { get; } | |||
/// <inheritdoc /> | |||
public ulong GuildId { get; private set; } | |||
/// <inheritdoc /> | |||
public ulong ChannelId { get; private set; } | |||
/// <inheritdoc /> | |||
public string XkcdCode { get; private set; } | |||
/// <inheritdoc /> | |||
public string GuildName { get; private set; } | |||
/// <inheritdoc /> | |||
public string ChannelName { get; private set; } | |||
/// <inheritdoc /> | |||
public string Url => $"{DiscordConfig.InviteUrl}/{XkcdCode ?? Code}"; | |||
/// <inheritdoc /> | |||
public string XkcdUrl => XkcdCode != null ? $"{DiscordConfig.InviteUrl}/{XkcdCode}" : null; | |||
internal Invite(IDiscordClient discord, Model model) | |||
{ | |||
Discord = discord; | |||
Code = model.Code; | |||
Update(model); | |||
} | |||
protected virtual void Update(Model model) | |||
{ | |||
XkcdCode = model.XkcdPass; | |||
GuildId = model.Guild.Id; | |||
ChannelId = model.Channel.Id; | |||
GuildName = model.Guild.Name; | |||
ChannelName = model.Channel.Name; | |||
} | |||
/// <inheritdoc /> | |||
public async Task Accept() | |||
{ | |||
await Discord.ApiClient.AcceptInvite(Code).ConfigureAwait(false); | |||
} | |||
/// <inheritdoc /> | |||
public async Task Delete() | |||
{ | |||
await Discord.ApiClient.DeleteInvite(Code).ConfigureAwait(false); | |||
} | |||
/// <inheritdoc /> | |||
public override string ToString() => XkcdUrl ?? Url; | |||
private string DebuggerDisplay => $"{XkcdUrl ?? Url} ({GuildName} / {ChannelName})"; | |||
string IEntity<string>.Id => Code; | |||
} | |||
} |
@@ -0,0 +1,32 @@ | |||
using Model = Discord.API.InviteMetadata; | |||
namespace Discord | |||
{ | |||
public class InviteMetadata : Invite, IInviteMetadata | |||
{ | |||
/// <inheritdoc /> | |||
public bool IsRevoked { get; private set; } | |||
/// <inheritdoc /> | |||
public bool IsTemporary { get; private set; } | |||
/// <inheritdoc /> | |||
public int? MaxAge { get; private set; } | |||
/// <inheritdoc /> | |||
public int? MaxUses { get; private set; } | |||
/// <inheritdoc /> | |||
public int Uses { get; private set; } | |||
internal InviteMetadata(IDiscordClient client, Model model) | |||
: base(client, model) | |||
{ | |||
Update(model); | |||
} | |||
private void Update(Model model) | |||
{ | |||
IsRevoked = model.Revoked; | |||
IsTemporary = model.Temporary; | |||
MaxAge = model.MaxAge != 0 ? model.MaxAge : (int?)null; | |||
MaxUses = model.MaxUses; | |||
Uses = model.Uses; | |||
} | |||
} | |||
} |
@@ -1,7 +1,7 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Threading.Tasks; | |||
using Discord.API.Rest; | |||
using System.Collections.Generic; | |||
namespace Discord | |||
{ |
@@ -1,6 +1,6 @@ | |||
namespace Discord | |||
{ | |||
internal enum ChannelPermission : byte | |||
public enum ChannelPermission : byte | |||
{ | |||
//General | |||
CreateInstantInvite = 0, |
@@ -0,0 +1,151 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
namespace Discord | |||
{ | |||
[DebuggerDisplay("{DebuggerDisplay,nq}")] | |||
public struct ChannelPermissions | |||
{ | |||
#if CSHARP7 | |||
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); | |||
#else | |||
private static ChannelPermissions _allDM { get; } = new ChannelPermissions(Convert.ToUInt64("00010000000000111111110000011001", 2)); | |||
private static ChannelPermissions _allText { get; } = new ChannelPermissions(Convert.ToUInt64("00000000000000011100110000000000", 2)); | |||
private static ChannelPermissions _allVoice { get; } = new ChannelPermissions(Convert.ToUInt64("00010011111100000000000000011001", 2)); | |||
#endif | |||
/// <summary> Gets a blank ChannelPermissions that grants no permissions. </summary> | |||
public static ChannelPermissions None { get; } = new ChannelPermissions(); | |||
/// <summary> Gets a ChannelPermissions that grants all permissions for a given channelType. </summary> | |||
public static ChannelPermissions All(IChannel channel) | |||
{ | |||
#if CSHARP7 | |||
switch (channel) | |||
{ | |||
case ITextChannel _: return _allText; | |||
case IVoiceChannel _: return _allVoice; | |||
case IDMChannel _: return _allDM; | |||
default: | |||
throw new ArgumentException("Unknown channel type", nameof(channel)); | |||
} | |||
#else | |||
if (channel is ITextChannel) return _allText; | |||
if (channel is IVoiceChannel) return _allVoice; | |||
if (channel is IDMChannel) return _allDM; | |||
throw new ArgumentException("Unknown channel type", nameof(channel)); | |||
#endif | |||
} | |||
/// <summary> Gets a packed value representing all the permissions in this ChannelPermissions. </summary> | |||
public ulong RawValue { get; } | |||
/// <summary> If True, a user may create invites. </summary> | |||
public bool CreateInstantInvite => Permissions.GetValue(RawValue, ChannelPermission.CreateInstantInvite); | |||
/// <summary> If True, a user may create, delete and modify this channel. </summary> | |||
public bool ManageChannel => Permissions.GetValue(RawValue, ChannelPermission.ManageChannel); | |||
/// <summary> If True, a user may join channels. </summary> | |||
public bool ReadMessages => Permissions.GetValue(RawValue, ChannelPermission.ReadMessages); | |||
/// <summary> If True, a user may send messages. </summary> | |||
public bool SendMessages => Permissions.GetValue(RawValue, ChannelPermission.SendMessages); | |||
/// <summary> If True, a user may send text-to-speech messages. </summary> | |||
public bool SendTTSMessages => Permissions.GetValue(RawValue, ChannelPermission.SendTTSMessages); | |||
/// <summary> If True, a user may delete messages. </summary> | |||
public bool ManageMessages => Permissions.GetValue(RawValue, ChannelPermission.ManageMessages); | |||
/// <summary> If True, Discord will auto-embed links sent by this user. </summary> | |||
public bool EmbedLinks => Permissions.GetValue(RawValue, ChannelPermission.EmbedLinks); | |||
/// <summary> If True, a user may send files. </summary> | |||
public bool AttachFiles => Permissions.GetValue(RawValue, ChannelPermission.AttachFiles); | |||
/// <summary> If True, a user may read previous messages. </summary> | |||
public bool ReadMessageHistory => Permissions.GetValue(RawValue, ChannelPermission.ReadMessageHistory); | |||
/// <summary> If True, a user may mention @everyone. </summary> | |||
public bool MentionEveryone => Permissions.GetValue(RawValue, ChannelPermission.MentionEveryone); | |||
/// <summary> If True, a user may connect to a voice channel. </summary> | |||
public bool Connect => Permissions.GetValue(RawValue, ChannelPermission.Connect); | |||
/// <summary> If True, a user may speak in a voice channel. </summary> | |||
public bool Speak => Permissions.GetValue(RawValue, ChannelPermission.Speak); | |||
/// <summary> If True, a user may mute users. </summary> | |||
public bool MuteMembers => Permissions.GetValue(RawValue, ChannelPermission.MuteMembers); | |||
/// <summary> If True, a user may deafen users. </summary> | |||
public bool DeafenMembers => Permissions.GetValue(RawValue, ChannelPermission.DeafenMembers); | |||
/// <summary> If True, a user may move other users between voice channels. </summary> | |||
public bool MoveMembers => Permissions.GetValue(RawValue, ChannelPermission.MoveMembers); | |||
/// <summary> If True, a user may use voice-activity-detection rather than push-to-talk. </summary> | |||
public bool UseVAD => Permissions.GetValue(RawValue, ChannelPermission.UseVAD); | |||
/// <summary> If True, a user may adjust permissions. This also implictly grants all other permissions. </summary> | |||
public bool ManagePermissions => Permissions.GetValue(RawValue, ChannelPermission.ManagePermissions); | |||
/// <summary> Creates a new ChannelPermissions with the provided packed value. </summary> | |||
public ChannelPermissions(ulong rawValue) { RawValue = rawValue; } | |||
private ChannelPermissions(ulong 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) | |||
{ | |||
ulong value = initialValue; | |||
Permissions.SetValue(ref value, createInstantInvite, ChannelPermission.CreateInstantInvite); | |||
Permissions.SetValue(ref value, manageChannel, ChannelPermission.ManageChannel); | |||
Permissions.SetValue(ref value, readMessages, ChannelPermission.ReadMessages); | |||
Permissions.SetValue(ref value, sendMessages, ChannelPermission.SendMessages); | |||
Permissions.SetValue(ref value, sendTTSMessages, ChannelPermission.SendTTSMessages); | |||
Permissions.SetValue(ref value, manageMessages, ChannelPermission.ManageMessages); | |||
Permissions.SetValue(ref value, embedLinks, ChannelPermission.EmbedLinks); | |||
Permissions.SetValue(ref value, attachFiles, ChannelPermission.AttachFiles); | |||
Permissions.SetValue(ref value, readMessageHistory, ChannelPermission.ReadMessageHistory); | |||
Permissions.SetValue(ref value, mentionEveryone, ChannelPermission.MentionEveryone); | |||
Permissions.SetValue(ref value, connect, ChannelPermission.Connect); | |||
Permissions.SetValue(ref value, speak, ChannelPermission.Speak); | |||
Permissions.SetValue(ref value, muteMembers, ChannelPermission.MuteMembers); | |||
Permissions.SetValue(ref value, deafenMembers, ChannelPermission.DeafenMembers); | |||
Permissions.SetValue(ref value, moveMembers, ChannelPermission.MoveMembers); | |||
Permissions.SetValue(ref value, useVoiceActivation, ChannelPermission.UseVAD); | |||
Permissions.SetValue(ref value, managePermissions, ChannelPermission.ManagePermissions); | |||
RawValue = value; | |||
} | |||
/// <summary> Creates a new ChannelPermissions with the provided permissions. </summary> | |||
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) { } | |||
/// <summary> Creates a new ChannelPermissions from this one, changing the provided non-null permissions. </summary> | |||
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 List<ChannelPermission> ToList() | |||
{ | |||
var perms = new List<ChannelPermission>(); | |||
ulong x = 1; | |||
for (byte i = 0; i < Permissions.MaxBits; i++, x <<= 1) | |||
{ | |||
if ((RawValue & x) != 0) | |||
perms.Add((ChannelPermission)i); | |||
} | |||
return perms; | |||
} | |||
/// <inheritdoc /> | |||
public override string ToString() => RawValue.ToString(); | |||
private string DebuggerDisplay => $"{RawValue} ({string.Join(", ", ToList())})"; | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
namespace Discord | |||
{ | |||
internal enum GuildPermission : byte | |||
public enum GuildPermission : byte | |||
{ | |||
//General | |||
CreateInstantInvite = 0, |
@@ -1,71 +1,78 @@ | |||
using System.Collections.Generic; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
namespace Discord | |||
{ | |||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
public struct GuildPermissions | |||
{ | |||
/// <summary> Gets a blank GuildPermissions that grants no permissions. </summary> | |||
public static readonly GuildPermissions None = new GuildPermissions(); | |||
/// <summary> Gets a GuildPermissions that grants all permissions. </summary> | |||
#if CSHARP7 | |||
public static readonly GuildPermissions All = new GuildPermissions(0b000111_111111_0011111111_0000111111); | |||
#else | |||
public static readonly GuildPermissions All = new GuildPermissions(Convert.ToUInt64("00011111111100111111110000111111", 2)); | |||
#endif | |||
/// <summary> Gets a packed value representing all the permissions in this GuildPermissions. </summary> | |||
public uint RawValue { get; } | |||
public ulong RawValue { get; } | |||
/// <summary> If True, a user may create invites. </summary> | |||
public bool CreateInstantInvite => PermissionUtilities.GetValue(RawValue, GuildPermission.CreateInstantInvite); | |||
public bool CreateInstantInvite => Permissions.GetValue(RawValue, GuildPermission.CreateInstantInvite); | |||
/// <summary> If True, a user may ban users from the guild. </summary> | |||
public bool BanMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.BanMembers); | |||
public bool BanMembers => Permissions.GetValue(RawValue, GuildPermission.BanMembers); | |||
/// <summary> If True, a user may kick users from the guild. </summary> | |||
public bool KickMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.KickMembers); | |||
public bool KickMembers => Permissions.GetValue(RawValue, GuildPermission.KickMembers); | |||
/// <summary> If True, a user is granted all permissions, and cannot have them revoked via channel permissions. </summary> | |||
public bool Administrator => PermissionUtilities.GetValue(RawValue, GuildPermission.Administrator); | |||
public bool Administrator => Permissions.GetValue(RawValue, GuildPermission.Administrator); | |||
/// <summary> If True, a user may create, delete and modify channels. </summary> | |||
public bool ManageChannels => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageChannels); | |||
public bool ManageChannels => Permissions.GetValue(RawValue, GuildPermission.ManageChannels); | |||
/// <summary> If True, a user may adjust guild properties. </summary> | |||
public bool ManageGuild => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageGuild); | |||
public bool ManageGuild => Permissions.GetValue(RawValue, GuildPermission.ManageGuild); | |||
/// <summary> If True, a user may join channels. </summary> | |||
public bool ReadMessages => PermissionUtilities.GetValue(RawValue, GuildPermission.ReadMessages); | |||
public bool ReadMessages => Permissions.GetValue(RawValue, GuildPermission.ReadMessages); | |||
/// <summary> If True, a user may send messages. </summary> | |||
public bool SendMessages => PermissionUtilities.GetValue(RawValue, GuildPermission.SendMessages); | |||
public bool SendMessages => Permissions.GetValue(RawValue, GuildPermission.SendMessages); | |||
/// <summary> If True, a user may send text-to-speech messages. </summary> | |||
public bool SendTTSMessages => PermissionUtilities.GetValue(RawValue, GuildPermission.SendTTSMessages); | |||
public bool SendTTSMessages => Permissions.GetValue(RawValue, GuildPermission.SendTTSMessages); | |||
/// <summary> If True, a user may delete messages. </summary> | |||
public bool ManageMessages => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageMessages); | |||
public bool ManageMessages => Permissions.GetValue(RawValue, GuildPermission.ManageMessages); | |||
/// <summary> If True, Discord will auto-embed links sent by this user. </summary> | |||
public bool EmbedLinks => PermissionUtilities.GetValue(RawValue, GuildPermission.EmbedLinks); | |||
public bool EmbedLinks => Permissions.GetValue(RawValue, GuildPermission.EmbedLinks); | |||
/// <summary> If True, a user may send files. </summary> | |||
public bool AttachFiles => PermissionUtilities.GetValue(RawValue, GuildPermission.AttachFiles); | |||
public bool AttachFiles => Permissions.GetValue(RawValue, GuildPermission.AttachFiles); | |||
/// <summary> If True, a user may read previous messages. </summary> | |||
public bool ReadMessageHistory => PermissionUtilities.GetValue(RawValue, GuildPermission.ReadMessageHistory); | |||
public bool ReadMessageHistory => Permissions.GetValue(RawValue, GuildPermission.ReadMessageHistory); | |||
/// <summary> If True, a user may mention @everyone. </summary> | |||
public bool MentionEveryone => PermissionUtilities.GetValue(RawValue, GuildPermission.MentionEveryone); | |||
public bool MentionEveryone => Permissions.GetValue(RawValue, GuildPermission.MentionEveryone); | |||
/// <summary> If True, a user may connect to a voice channel. </summary> | |||
public bool Connect => PermissionUtilities.GetValue(RawValue, GuildPermission.Connect); | |||
public bool Connect => Permissions.GetValue(RawValue, GuildPermission.Connect); | |||
/// <summary> If True, a user may speak in a voice channel. </summary> | |||
public bool Speak => PermissionUtilities.GetValue(RawValue, GuildPermission.Speak); | |||
public bool Speak => Permissions.GetValue(RawValue, GuildPermission.Speak); | |||
/// <summary> If True, a user may mute users. </summary> | |||
public bool MuteMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.MuteMembers); | |||
public bool MuteMembers => Permissions.GetValue(RawValue, GuildPermission.MuteMembers); | |||
/// <summary> If True, a user may deafen users. </summary> | |||
public bool DeafenMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.DeafenMembers); | |||
public bool DeafenMembers => Permissions.GetValue(RawValue, GuildPermission.DeafenMembers); | |||
/// <summary> If True, a user may move other users between voice channels. </summary> | |||
public bool MoveMembers => PermissionUtilities.GetValue(RawValue, GuildPermission.MoveMembers); | |||
public bool MoveMembers => Permissions.GetValue(RawValue, GuildPermission.MoveMembers); | |||
/// <summary> If True, a user may use voice-activity-detection rather than push-to-talk. </summary> | |||
public bool UseVAD => PermissionUtilities.GetValue(RawValue, GuildPermission.UseVAD); | |||
public bool UseVAD => Permissions.GetValue(RawValue, GuildPermission.UseVAD); | |||
/// <summary> If True, a user may change their own nickname. </summary> | |||
public bool ChangeNickname => PermissionUtilities.GetValue(RawValue, GuildPermission.ChangeNickname); | |||
public bool ChangeNickname => Permissions.GetValue(RawValue, GuildPermission.ChangeNickname); | |||
/// <summary> If True, a user may change the nickname of other users. </summary> | |||
public bool ManageNicknames => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageNicknames); | |||
public bool ManageNicknames => Permissions.GetValue(RawValue, GuildPermission.ManageNicknames); | |||
/// <summary> If True, a user may adjust roles. </summary> | |||
public bool ManageRoles => PermissionUtilities.GetValue(RawValue, GuildPermission.ManageRoles); | |||
public bool ManageRoles => Permissions.GetValue(RawValue, GuildPermission.ManageRoles); | |||
/// <summary> Creates a new GuildPermissions with the provided packed value. </summary> | |||
public GuildPermissions(uint rawValue) { RawValue = rawValue; } | |||
public GuildPermissions(ulong rawValue) { RawValue = rawValue; } | |||
private GuildPermissions(uint initialValue, bool? createInstantInvite = null, bool? kickMembers = null, | |||
private GuildPermissions(ulong 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, | |||
@@ -73,31 +80,31 @@ namespace Discord | |||
bool? moveMembers = null, bool? useVoiceActivation = null, bool? changeNickname = null, bool? manageNicknames = null, | |||
bool? manageRoles = null) | |||
{ | |||
uint value = initialValue; | |||
ulong 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); | |||
Permissions.SetValue(ref value, createInstantInvite, GuildPermission.CreateInstantInvite); | |||
Permissions.SetValue(ref value, banMembers, GuildPermission.BanMembers); | |||
Permissions.SetValue(ref value, kickMembers, GuildPermission.KickMembers); | |||
Permissions.SetValue(ref value, administrator, GuildPermission.Administrator); | |||
Permissions.SetValue(ref value, manageChannel, GuildPermission.ManageChannels); | |||
Permissions.SetValue(ref value, manageGuild, GuildPermission.ManageGuild); | |||
Permissions.SetValue(ref value, readMessages, GuildPermission.ReadMessages); | |||
Permissions.SetValue(ref value, sendMessages, GuildPermission.SendMessages); | |||
Permissions.SetValue(ref value, sendTTSMessages, GuildPermission.SendTTSMessages); | |||
Permissions.SetValue(ref value, manageMessages, GuildPermission.ManageMessages); | |||
Permissions.SetValue(ref value, embedLinks, GuildPermission.EmbedLinks); | |||
Permissions.SetValue(ref value, attachFiles, GuildPermission.AttachFiles); | |||
Permissions.SetValue(ref value, readMessageHistory, GuildPermission.ReadMessageHistory); | |||
Permissions.SetValue(ref value, mentionEveryone, GuildPermission.MentionEveryone); | |||
Permissions.SetValue(ref value, connect, GuildPermission.Connect); | |||
Permissions.SetValue(ref value, speak, GuildPermission.Speak); | |||
Permissions.SetValue(ref value, muteMembers, GuildPermission.MuteMembers); | |||
Permissions.SetValue(ref value, deafenMembers, GuildPermission.DeafenMembers); | |||
Permissions.SetValue(ref value, moveMembers, GuildPermission.MoveMembers); | |||
Permissions.SetValue(ref value, useVoiceActivation, GuildPermission.UseVAD); | |||
Permissions.SetValue(ref value, changeNickname, GuildPermission.ChangeNickname); | |||
Permissions.SetValue(ref value, manageNicknames, GuildPermission.ManageNicknames); | |||
Permissions.SetValue(ref value, manageRoles, GuildPermission.ManageRoles); | |||
RawValue = value; | |||
} | |||
@@ -125,21 +132,20 @@ namespace Discord | |||
=> 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); | |||
/// <inheritdoc /> | |||
public override string ToString() | |||
public List<GuildPermission> ToList() | |||
{ | |||
var perms = new List<string>(); | |||
int x = 1; | |||
for (byte i = 0; i < 32; i++, x <<= 1) | |||
var perms = new List<GuildPermission>(); | |||
ulong x = 1; | |||
for (byte i = 0; i < Permissions.MaxBits; i++, x <<= 1) | |||
{ | |||
if ((RawValue & x) != 0) | |||
{ | |||
if (System.Enum.IsDefined(typeof(GuildPermission), i)) | |||
perms.Add($"{(GuildPermission)i}"); | |||
} | |||
perms.Add((GuildPermission)i); | |||
} | |||
return string.Join(", ", perms); | |||
return perms; | |||
} | |||
/// <inheritdoc /> | |||
public override string ToString() => RawValue.ToString(); | |||
private string DebuggerDisplay => $"{RawValue} ({string.Join(", ", ToList())})"; | |||
} | |||
} |
@@ -1,8 +1,10 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
namespace Discord | |||
{ | |||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
public struct OverwritePermissions | |||
{ | |||
/// <summary> Gets a blank OverwritePermissions that inherits all permissions. </summary> | |||
@@ -15,77 +17,77 @@ namespace Discord | |||
=> new OverwritePermissions(0, ChannelPermissions.All(channel).RawValue); | |||
/// <summary> Gets a packed value representing all the allowed permissions in this OverwritePermissions. </summary> | |||
public uint AllowValue { get; } | |||
public ulong AllowValue { get; } | |||
/// <summary> Gets a packed value representing all the denied permissions in this OverwritePermissions. </summary> | |||
public uint DenyValue { get; } | |||
public ulong DenyValue { get; } | |||
/// <summary> If True, a user may create invites. </summary> | |||
public PermValue CreateInstantInvite => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.CreateInstantInvite); | |||
public PermValue CreateInstantInvite => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.CreateInstantInvite); | |||
/// <summary> If True, a user may create, delete and modify this channel. </summary> | |||
public PermValue ManageChannel => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ManageChannel); | |||
public PermValue ManageChannel => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ManageChannel); | |||
/// <summary> If True, a user may join channels. </summary> | |||
public PermValue ReadMessages => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ReadMessages); | |||
public PermValue ReadMessages => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ReadMessages); | |||
/// <summary> If True, a user may send messages. </summary> | |||
public PermValue SendMessages => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.SendMessages); | |||
public PermValue SendMessages => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.SendMessages); | |||
/// <summary> If True, a user may send text-to-speech messages. </summary> | |||
public PermValue SendTTSMessages => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.SendTTSMessages); | |||
public PermValue SendTTSMessages => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.SendTTSMessages); | |||
/// <summary> If True, a user may delete messages. </summary> | |||
public PermValue ManageMessages => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ManageMessages); | |||
public PermValue ManageMessages => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ManageMessages); | |||
/// <summary> If True, Discord will auto-embed links sent by this user. </summary> | |||
public PermValue EmbedLinks => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.EmbedLinks); | |||
public PermValue EmbedLinks => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.EmbedLinks); | |||
/// <summary> If True, a user may send files. </summary> | |||
public PermValue AttachFiles => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.AttachFiles); | |||
public PermValue AttachFiles => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.AttachFiles); | |||
/// <summary> If True, a user may read previous messages. </summary> | |||
public PermValue ReadMessageHistory => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ReadMessageHistory); | |||
public PermValue ReadMessageHistory => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ReadMessageHistory); | |||
/// <summary> If True, a user may mention @everyone. </summary> | |||
public PermValue MentionEveryone => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.MentionEveryone); | |||
public PermValue MentionEveryone => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.MentionEveryone); | |||
/// <summary> If True, a user may connect to a voice channel. </summary> | |||
public PermValue Connect => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.Connect); | |||
public PermValue Connect => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.Connect); | |||
/// <summary> If True, a user may speak in a voice channel. </summary> | |||
public PermValue Speak => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.Speak); | |||
public PermValue Speak => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.Speak); | |||
/// <summary> If True, a user may mute users. </summary> | |||
public PermValue MuteMembers => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.MuteMembers); | |||
public PermValue MuteMembers => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.MuteMembers); | |||
/// <summary> If True, a user may deafen users. </summary> | |||
public PermValue DeafenMembers => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.DeafenMembers); | |||
public PermValue DeafenMembers => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.DeafenMembers); | |||
/// <summary> If True, a user may move other users between voice channels. </summary> | |||
public PermValue MoveMembers => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.MoveMembers); | |||
public PermValue MoveMembers => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.MoveMembers); | |||
/// <summary> If True, a user may use voice-activity-detection rather than push-to-talk. </summary> | |||
public PermValue UseVAD => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.UseVAD); | |||
public PermValue UseVAD => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.UseVAD); | |||
/// <summary> If True, a user may adjust permissions. This also implictly grants all other permissions. </summary> | |||
public PermValue ManagePermissions => PermissionUtilities.GetValue(AllowValue, DenyValue, ChannelPermission.ManagePermissions); | |||
public PermValue ManagePermissions => Permissions.GetValue(AllowValue, DenyValue, ChannelPermission.ManagePermissions); | |||
/// <summary> Creates a new OverwritePermissions with the provided allow and deny packed values. </summary> | |||
public OverwritePermissions(uint allowValue, uint denyValue) | |||
public OverwritePermissions(ulong allowValue, ulong denyValue) | |||
{ | |||
AllowValue = allowValue; | |||
DenyValue = denyValue; | |||
} | |||
private OverwritePermissions(uint allowValue, uint denyValue, PermValue? createInstantInvite = null, PermValue? manageChannel = null, | |||
private OverwritePermissions(ulong allowValue, ulong 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); | |||
Permissions.SetValue(ref allowValue, ref denyValue, createInstantInvite, ChannelPermission.CreateInstantInvite); | |||
Permissions.SetValue(ref allowValue, ref denyValue, manageChannel, ChannelPermission.ManageChannel); | |||
Permissions.SetValue(ref allowValue, ref denyValue, readMessages, ChannelPermission.ReadMessages); | |||
Permissions.SetValue(ref allowValue, ref denyValue, sendMessages, ChannelPermission.SendMessages); | |||
Permissions.SetValue(ref allowValue, ref denyValue, sendTTSMessages, ChannelPermission.SendTTSMessages); | |||
Permissions.SetValue(ref allowValue, ref denyValue, manageMessages, ChannelPermission.ManageMessages); | |||
Permissions.SetValue(ref allowValue, ref denyValue, embedLinks, ChannelPermission.EmbedLinks); | |||
Permissions.SetValue(ref allowValue, ref denyValue, attachFiles, ChannelPermission.AttachFiles); | |||
Permissions.SetValue(ref allowValue, ref denyValue, readMessageHistory, ChannelPermission.ReadMessageHistory); | |||
Permissions.SetValue(ref allowValue, ref denyValue, mentionEveryone, ChannelPermission.MentionEveryone); | |||
Permissions.SetValue(ref allowValue, ref denyValue, connect, ChannelPermission.Connect); | |||
Permissions.SetValue(ref allowValue, ref denyValue, speak, ChannelPermission.Speak); | |||
Permissions.SetValue(ref allowValue, ref denyValue, muteMembers, ChannelPermission.MuteMembers); | |||
Permissions.SetValue(ref allowValue, ref denyValue, deafenMembers, ChannelPermission.DeafenMembers); | |||
Permissions.SetValue(ref allowValue, ref denyValue, moveMembers, ChannelPermission.MoveMembers); | |||
Permissions.SetValue(ref allowValue, ref denyValue, useVoiceActivation, ChannelPermission.UseVAD); | |||
Permissions.SetValue(ref allowValue, ref denyValue, managePermissions, ChannelPermission.ManagePermissions); | |||
AllowValue = allowValue; | |||
DenyValue = denyValue; | |||
@@ -111,25 +113,32 @@ namespace Discord | |||
embedLinks, attachFiles, readMessageHistory, mentionEveryone, connect, speak, muteMembers, deafenMembers, | |||
moveMembers, useVoiceActivation, managePermissions); | |||
/// <inheritdoc /> | |||
public override string ToString() | |||
public List<ChannelPermission> ToAllowList() | |||
{ | |||
var perms = new List<string>(); | |||
int x = 1; | |||
for (byte i = 0; i < 32; i++, x <<= 1) | |||
var perms = new List<ChannelPermission>(); | |||
ulong x = 1; | |||
for (byte i = 0; i < Permissions.MaxBits; 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}"); | |||
} | |||
perms.Add((ChannelPermission)i); | |||
} | |||
return perms; | |||
} | |||
public List<ChannelPermission> ToDenyList() | |||
{ | |||
var perms = new List<ChannelPermission>(); | |||
ulong x = 1; | |||
for (byte i = 0; i < Permissions.MaxBits; i++, x <<= 1) | |||
{ | |||
if ((DenyValue & x) != 0) | |||
perms.Add((ChannelPermission)i); | |||
} | |||
return string.Join(", ", perms); | |||
return perms; | |||
} | |||
/// <inheritdoc /> | |||
public override string ToString() => $"Allow {AllowValue}, Deny {DenyValue}"; | |||
private string DebuggerDisplay => | |||
$"Allow {AllowValue} ({string.Join(", ", ToAllowList())})\n" + | |||
$"Deny {DenyValue} ({string.Join(", ", ToDenyList())})"; | |||
} | |||
} |
@@ -0,0 +1,159 @@ | |||
using System.Runtime.CompilerServices; | |||
namespace Discord | |||
{ | |||
internal static class Permissions | |||
{ | |||
public const int MaxBits = 53; | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static PermValue GetValue(ulong allow, ulong deny, ChannelPermission bit) | |||
=> GetValue(allow, deny, (byte)bit); | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static PermValue GetValue(ulong allow, ulong deny, GuildPermission bit) | |||
=> GetValue(allow, deny, (byte)bit); | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static PermValue GetValue(ulong allow, ulong 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(ulong value, ChannelPermission bit) | |||
=> GetValue(value, (byte)bit); | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static bool GetValue(ulong value, GuildPermission bit) | |||
=> GetValue(value, (byte)bit); | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static bool GetValue(ulong value, byte bit) => HasBit(value, bit); | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void SetValue(ref ulong rawValue, bool? value, ChannelPermission bit) | |||
=> SetValue(ref rawValue, value, (byte)bit); | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void SetValue(ref ulong rawValue, bool? value, GuildPermission bit) | |||
=> SetValue(ref rawValue, value, (byte)bit); | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void SetValue(ref ulong 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 ulong allow, ref ulong deny, PermValue? value, ChannelPermission bit) | |||
=> SetValue(ref allow, ref deny, value, (byte)bit); | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void SetValue(ref ulong allow, ref ulong deny, PermValue? value, GuildPermission bit) | |||
=> SetValue(ref allow, ref deny, value, (byte)bit); | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void SetValue(ref ulong allow, ref ulong 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(ulong value, byte bit) => (value & (1U << bit)) != 0; | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void SetBit(ref ulong value, byte bit) => value |= (1U << bit); | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void UnsetBit(ref ulong value, byte bit) => value &= ~(1U << bit); | |||
public static ulong ResolveGuild(IGuildUser user) | |||
{ | |||
var roles = user.Roles; | |||
ulong newPermissions = 0; | |||
for (int i = 0; i < roles.Count; i++) | |||
newPermissions |= roles[i].Permissions.RawValue; | |||
return newPermissions; | |||
} | |||
/*public static ulong ResolveChannel(IGuildUser user, IGuildChannel channel) | |||
{ | |||
return ResolveChannel(user, channel, ResolveGuild(user)); | |||
}*/ | |||
public static ulong ResolveChannel(IGuildUser user, IGuildChannel channel, ulong guildPermissions) | |||
{ | |||
ulong resolvedPermissions = 0; | |||
ulong mask = ChannelPermissions.All(channel).RawValue; | |||
if (user.Id == user.Guild.OwnerId || GetValue(resolvedPermissions, GuildPermission.Administrator)) | |||
resolvedPermissions = mask; //Owners and administrators always have all permissions | |||
else | |||
{ | |||
//Start with this user's guild permissions | |||
resolvedPermissions = guildPermissions; | |||
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; | |||
#if CSHARP7 | |||
switch (channel) | |||
{ | |||
case ITextChannel _: | |||
if (!GetValue(resolvedPermissions, ChannelPermission.ReadMessages)) | |||
resolvedPermissions = 0; //No read permission on a text channel removes all other permissions | |||
break; | |||
case IVoiceChannel _: | |||
if (!GetValue(resolvedPermissions, ChannelPermission.Connect)) | |||
resolvedPermissions = 0; //No read permission on a text channel removes all other permissions | |||
break; | |||
} | |||
#else | |||
var textChannel = channel as ITextChannel; | |||
var voiceChannel = channel as IVoiceChannel; | |||
if (textChannel != null && !GetValue(resolvedPermissions, ChannelPermission.ReadMessages)) | |||
resolvedPermissions = 0; //No read permission on a text channel removes all other permissions | |||
else if (voiceChannel != null && !GetValue(resolvedPermissions, ChannelPermission.Connect)) | |||
resolvedPermissions = 0; //No connect permission on a voice channel removes all other permissions | |||
#endif | |||
resolvedPermissions &= mask; //Ensure we didnt get any permissions this channel doesnt support (from guildPerms, for example) | |||
} | |||
return resolvedPermissions; | |||
} | |||
} | |||
} |
@@ -0,0 +1,31 @@ | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
using Model = Discord.API.Connection; | |||
namespace Discord | |||
{ | |||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
public class Connection : IConnection | |||
{ | |||
public string Id { get; } | |||
public string Type { get; } | |||
public string Name { get; } | |||
public bool IsRevoked { get; } | |||
public IEnumerable<ulong> IntegrationIds { get; } | |||
public Connection(Model model) | |||
{ | |||
Id = model.Id; | |||
Type = model.Type; | |||
Name = model.Name; | |||
IsRevoked = model.Revoked; | |||
IntegrationIds = model.Integrations; | |||
} | |||
public override string ToString() => Name; | |||
private string DebuggerDisplay => $"{Name} ({Id}, Type = {Type}{(IsRevoked ? ", Revoked" : "")})"; | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
namespace Discord | |||
{ | |||
public struct Game | |||
{ | |||
public string Name { get; } | |||
public string StreamUrl { get; } | |||
public StreamType StreamType { get; } | |||
public Game(string name) | |||
{ | |||
Name = name; | |||
StreamUrl = null; | |||
StreamType = StreamType.NotStreaming; | |||
} | |||
public Game(string name, string streamUrl, StreamType type) | |||
{ | |||
Name = name; | |||
StreamUrl = streamUrl; | |||
StreamType = type; | |||
} | |||
} | |||
} |
@@ -9,6 +9,6 @@ namespace Discord | |||
string Name { get; } | |||
bool IsRevoked { get; } | |||
IEnumerable<ulong> Integrations { get; } | |||
IEnumerable<ulong> IntegrationIds { get; } | |||
} | |||
} |
@@ -21,17 +21,14 @@ namespace Discord | |||
IGuild Guild { get; } | |||
/// <summary> Returns a collection of the roles this user is a member of in this guild, including the guild's @everyone role. </summary> | |||
IReadOnlyList<IRole> Roles { get; } | |||
/// <summary> Gets the id of the voice channel this user is currently in, if any. </summary> | |||
ulong? VoiceChannelId { get; } | |||
/// <summary> Gets the voice channel this user is currently in, if any. </summary> | |||
IVoiceChannel VoiceChannel { get; } | |||
/// <summary> Gets the guild-level permissions granted to this user by their roles. </summary> | |||
GuildPermissions GetGuildPermissions(); | |||
/// <summary> Gets the channel-level permissions granted to this user for a given channel. </summary> | |||
ChannelPermissions GetPermissions(IGuildChannel channel); | |||
/// <summary> Return true if this user has the provided role. </summary> | |||
bool HasRole(IRole role); | |||
/// <summary> Kicks this user from this guild. </summary> | |||
Task Kick(); | |||
/// <summary> Modifies this user's properties in this guild. </summary> |
@@ -7,7 +7,7 @@ namespace Discord | |||
/// <summary> Gets the url to this user's avatar. </summary> | |||
string AvatarUrl { get; } | |||
/// <summary> Gets the game this user is currently playing, if any. </summary> | |||
string CurrentGame { get; } | |||
Game? CurrentGame { get; } | |||
/// <summary> Gets the per-username unique id for this user. </summary> | |||
ushort Discriminator { get; } | |||
/// <summary> Returns true if this user is a bot account. </summary> | |||
@@ -17,6 +17,7 @@ namespace Discord | |||
/// <summary> Gets the username for this user. </summary> | |||
string Username { get; } | |||
//TODO: CreateDMChannel is a candidate to move to IGuildUser, and User made a common class, depending on next friends list update | |||
/// <summary> Returns a private message channel to this user, creating one if it does not already exist. </summary> | |||
Task<IDMChannel> CreateDMChannel(); | |||
} |
@@ -0,0 +1,8 @@ | |||
namespace Discord | |||
{ | |||
public enum StreamType | |||
{ | |||
NotStreaming = 0, | |||
Twitch = 1 | |||
} | |||
} |
@@ -0,0 +1,46 @@ | |||
using System; | |||
using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
internal static class EventExtensions | |||
{ | |||
//TODO: Optimize these for if there is only 1 subscriber (can we do this?) | |||
public static async Task Raise(this Func<Task> eventHandler) | |||
{ | |||
var subscriptions = eventHandler?.GetInvocationList(); | |||
if (subscriptions != null) | |||
{ | |||
for (int i = 0; i < subscriptions.Length; i++) | |||
await (subscriptions[i] as Func<Task>).Invoke().ConfigureAwait(false); | |||
} | |||
} | |||
public static async Task Raise<T>(this Func<T, Task> eventHandler, T arg) | |||
{ | |||
var subscriptions = eventHandler?.GetInvocationList(); | |||
if (subscriptions != null) | |||
{ | |||
for (int i = 0; i < subscriptions.Length; i++) | |||
await (subscriptions[i] as Func<T, Task>).Invoke(arg).ConfigureAwait(false); | |||
} | |||
} | |||
public static async Task Raise<T1, T2>(this Func<T1, T2, Task> eventHandler, T1 arg1, T2 arg2) | |||
{ | |||
var subscriptions = eventHandler?.GetInvocationList(); | |||
if (subscriptions != null) | |||
{ | |||
for (int i = 0; i < subscriptions.Length; i++) | |||
await (subscriptions[i] as Func<T1, T2, Task>).Invoke(arg1, arg2).ConfigureAwait(false); | |||
} | |||
} | |||
public static async Task Raise<T1, T2, T3>(this Func<T1, T2, T3, Task> eventHandler, T1 arg1, T2 arg2, T3 arg3) | |||
{ | |||
var subscriptions = eventHandler?.GetInvocationList(); | |||
if (subscriptions != null) | |||
{ | |||
for (int i = 0; i < subscriptions.Length; i++) | |||
await (subscriptions[i] as Func<T1, T2, T3, Task>).Invoke(arg1, arg2, arg3).ConfigureAwait(false); | |||
} | |||
} | |||
} | |||
} |