@@ -164,8 +164,7 @@ namespace Discord.Commands | |||||
try | try | ||||
{ | { | ||||
ModuleInfo module; | ModuleInfo module; | ||||
_typedModuleDefs.TryGetValue(type, out module); | |||||
if (module == default(ModuleInfo)) | |||||
if (!_typedModuleDefs.TryRemove(type, out module)) | |||||
return false; | return false; | ||||
return RemoveModuleInternal(module); | return RemoveModuleInternal(module); | ||||
@@ -2,18 +2,19 @@ | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
//Source: https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/DateTimeOffset.cs | |||||
internal static class DateTimeUtils | internal static class DateTimeUtils | ||||
{ | { | ||||
#if !NETSTANDARD1_3 | #if !NETSTANDARD1_3 | ||||
//https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/DateTimeOffset.cs | |||||
private const long UnixEpochTicks = 621355968000000000; | |||||
private const long UnixEpochSeconds = 62135596800; | |||||
private const long UnixEpochTicks = 621_355_968_000_000_000; | |||||
private const long UnixEpochSeconds = 62_135_596_800; | |||||
private const long UnixEpochMilliseconds = 62_135_596_800_000; | |||||
#endif | #endif | ||||
public static DateTimeOffset FromSnowflake(ulong value) | public static DateTimeOffset FromSnowflake(ulong value) | ||||
=> FromUnixMilliseconds((long)((value >> 22) + 1420070400000UL)); | => FromUnixMilliseconds((long)((value >> 22) + 1420070400000UL)); | ||||
public static ulong ToSnowflake(DateTimeOffset value) | public static ulong ToSnowflake(DateTimeOffset value) | ||||
=> (ulong)(ToUnixMilliseconds(value) - 1420070400000L) << 22; | |||||
=> ((ulong)ToUnixMilliseconds(value) - 1420070400000UL) << 22; | |||||
public static DateTimeOffset FromTicks(long ticks) | public static DateTimeOffset FromTicks(long ticks) | ||||
=> new DateTimeOffset(ticks, TimeSpan.Zero); | => new DateTimeOffset(ticks, TimeSpan.Zero); | ||||
@@ -29,12 +30,12 @@ namespace Discord | |||||
return new DateTimeOffset(ticks, TimeSpan.Zero); | return new DateTimeOffset(ticks, TimeSpan.Zero); | ||||
#endif | #endif | ||||
} | } | ||||
public static DateTimeOffset FromUnixMilliseconds(long seconds) | |||||
public static DateTimeOffset FromUnixMilliseconds(long milliseconds) | |||||
{ | { | ||||
#if NETSTANDARD1_3 | #if NETSTANDARD1_3 | ||||
return DateTimeOffset.FromUnixTimeMilliseconds(seconds); | |||||
return DateTimeOffset.FromUnixTimeMilliseconds(milliseconds); | |||||
#else | #else | ||||
long ticks = seconds * TimeSpan.TicksPerMillisecond + UnixEpochTicks; | |||||
long ticks = milliseconds * TimeSpan.TicksPerMillisecond + UnixEpochTicks; | |||||
return new DateTimeOffset(ticks, TimeSpan.Zero); | return new DateTimeOffset(ticks, TimeSpan.Zero); | ||||
#endif | #endif | ||||
} | } | ||||
@@ -53,8 +54,8 @@ namespace Discord | |||||
#if NETSTANDARD1_3 | #if NETSTANDARD1_3 | ||||
return dto.ToUnixTimeMilliseconds(); | return dto.ToUnixTimeMilliseconds(); | ||||
#else | #else | ||||
long seconds = dto.UtcDateTime.Ticks / TimeSpan.TicksPerMillisecond; | |||||
return seconds - UnixEpochSeconds; | |||||
long milliseconds = dto.UtcDateTime.Ticks / TimeSpan.TicksPerMillisecond; | |||||
return milliseconds - UnixEpochMilliseconds; | |||||
#endif | #endif | ||||
} | } | ||||
} | } | ||||
@@ -185,9 +185,12 @@ namespace Discord | |||||
// Bulk Delete | // Bulk Delete | ||||
public static void YoungerThanTwoWeeks(ulong[] collection, string name) | public static void YoungerThanTwoWeeks(ulong[] collection, string name) | ||||
{ | { | ||||
var minimum = DateTimeUtils.ToSnowflake(DateTimeOffset.Now.Subtract(TimeSpan.FromMilliseconds(1209540000))); | |||||
var minimum = DateTimeUtils.ToSnowflake(DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays(14))); | |||||
for (var i = 0; i < collection.Length; i++) | for (var i = 0; i < collection.Length; i++) | ||||
if (collection[i] <= minimum) throw new ArgumentOutOfRangeException(name, "Messages must be younger than two weeks to delete."); | |||||
{ | |||||
if (collection[i] <= minimum) | |||||
throw new ArgumentOutOfRangeException(name, "Messages must be younger than two weeks old."); | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -494,13 +494,8 @@ namespace Discord.API | |||||
if (args.Content.GetValueOrDefault(null) == null) | if (args.Content.GetValueOrDefault(null) == null) | ||||
args.Content = ""; | args.Content = ""; | ||||
else if (args.Content.IsSpecified) | |||||
{ | |||||
if (args.Content.Value == null) | |||||
args.Content = ""; | |||||
if (args.Content.Value?.Length > DiscordConfig.MaxMessageSize) | |||||
throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content)); | |||||
} | |||||
else if (args.Content.IsSpecified && args.Content.Value?.Length > DiscordConfig.MaxMessageSize) | |||||
throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content)); | |||||
var ids = new BucketIds(channelId: channelId); | var ids = new BucketIds(channelId: channelId); | ||||
return await SendMultipartAsync<Message>("POST", () => $"channels/{channelId}/messages", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | return await SendMultipartAsync<Message>("POST", () => $"channels/{channelId}/messages", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); | ||||
@@ -101,7 +101,14 @@ namespace Discord.Net.Rest | |||||
if (p.Value is MultipartFile) | if (p.Value is MultipartFile) | ||||
{ | { | ||||
var fileValue = (MultipartFile)p.Value; | var fileValue = (MultipartFile)p.Value; | ||||
content.Add(new StreamContent(fileValue.Stream), p.Key, fileValue.Filename); | |||||
var stream = fileValue.Stream; | |||||
if (!stream.CanSeek) | |||||
{ | |||||
var memoryStream = new MemoryStream(); | |||||
await stream.CopyToAsync(memoryStream).ConfigureAwait(false); | |||||
stream = memoryStream; | |||||
} | |||||
content.Add(new StreamContent(stream), p.Key, fileValue.Filename); | |||||
continue; | continue; | ||||
} | } | ||||
@@ -7,8 +7,8 @@ namespace Discord.Rpc | |||||
public class RpcChannelSummary | public class RpcChannelSummary | ||||
{ | { | ||||
public ulong Id { get; } | public ulong Id { get; } | ||||
public string Name { get; set; } | |||||
public ChannelType Type { get; set; } | |||||
public string Name { get; private set; } | |||||
public ChannelType Type { get; private set; } | |||||
internal RpcChannelSummary(ulong id) | internal RpcChannelSummary(ulong id) | ||||
{ | { | ||||
@@ -29,6 +29,14 @@ namespace Discord.WebSocket | |||||
internal override void Update(ClientState state, PresenceModel model) | internal override void Update(ClientState state, PresenceModel model) | ||||
{ | { | ||||
if (model.User.Avatar.IsSpecified) | |||||
AvatarId = model.User.Avatar.Value; | |||||
if (model.User.Discriminator.IsSpecified) | |||||
DiscriminatorValue = ushort.Parse(model.User.Discriminator.Value); | |||||
if (model.User.Bot.IsSpecified) | |||||
IsBot = model.User.Bot.Value; | |||||
if (model.User.Username.IsSpecified) | |||||
Username = model.User.Username.Value; | |||||
} | } | ||||
internal new SocketSimpleUser Clone() => MemberwiseClone() as SocketSimpleUser; | internal new SocketSimpleUser Clone() => MemberwiseClone() as SocketSimpleUser; | ||||