Files
Discord.Net/src/Discord.Net.Rest/Entities/Users/RestUser.cs
Chris Johnston 606dac3e1a fix: Use double precision for X-Reset-After, set CultureInfo when parsing numeric types (#1375)
* Parse double for X-Reset-After instead of float, needs more precision

Float did not contain enough precision to store the millisecond unix
time value, which resulted in the second and millisecond values being
slightly off.

This can be easily tested using:

```cs
> DateTimeOffset.FromUnixTimeMilliseconds((long)(1470173022.123f *
1000)).Millisecond
160 // wrong

> DateTimeOffset.FromUnixTimeMilliseconds((long)(1470173022.123 *
1000)).Millisecond
123 // correct
```

* Parse RateLimit-Reset using an IFormatProvider

* State NumberStyle and use CultureInfo.InvariantCulture for any parsing

This updates most occurances in the code where a Parse or TryParse method was used to explicitly state the NumberStyle, and to use CultureInfo.InvariantCulture.
CultureInfo was used over NumberInfo, as it also works on DateTime parsing too.

* Use default format spec in Commands
2019-09-14 16:38:26 +00:00

108 lines
4.3 KiB
C#

using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.Threading.Tasks;
using Model = Discord.API.User;
namespace Discord.Rest
{
/// <summary>
/// Represents a REST-based user.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RestUser : RestEntity<ulong>, IUser, IUpdateable
{
/// <inheritdoc />
public bool IsBot { get; private set; }
/// <inheritdoc />
public string Username { get; private set; }
/// <inheritdoc />
public ushort DiscriminatorValue { get; private set; }
/// <inheritdoc />
public string AvatarId { get; private set; }
/// <inheritdoc />
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id);
/// <inheritdoc />
public string Discriminator => DiscriminatorValue.ToString("D4");
/// <inheritdoc />
public string Mention => MentionUtils.MentionUser(Id);
/// <inheritdoc />
public virtual IActivity Activity => null;
/// <inheritdoc />
public virtual UserStatus Status => UserStatus.Offline;
/// <inheritdoc />
public virtual IImmutableSet<ClientType> ActiveClients => ImmutableHashSet<ClientType>.Empty;
/// <inheritdoc />
public virtual bool IsWebhook => false;
internal RestUser(BaseDiscordClient discord, ulong id)
: base(discord, id)
{
}
internal static RestUser Create(BaseDiscordClient discord, Model model)
=> Create(discord, null, model, null);
internal static RestUser Create(BaseDiscordClient discord, IGuild guild, Model model, ulong? webhookId)
{
RestUser entity;
if (webhookId.HasValue)
entity = new RestWebhookUser(discord, guild, model.Id, webhookId.Value);
else
entity = new RestUser(discord, model.Id);
entity.Update(model);
return entity;
}
internal virtual void Update(Model model)
{
if (model.Avatar.IsSpecified)
AvatarId = model.Avatar.Value;
if (model.Discriminator.IsSpecified)
DiscriminatorValue = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture);
if (model.Bot.IsSpecified)
IsBot = model.Bot.Value;
if (model.Username.IsSpecified)
Username = model.Username.Value;
}
/// <inheritdoc />
public virtual async Task UpdateAsync(RequestOptions options = null)
{
var model = await Discord.ApiClient.GetUserAsync(Id, options).ConfigureAwait(false);
Update(model);
}
/// <summary>
/// Returns a direct message channel to this user, or create one if it does not already exist.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a rest DM channel where the user is the recipient.
/// </returns>
public Task<RestDMChannel> GetOrCreateDMChannelAsync(RequestOptions options = null)
=> UserHelper.CreateDMChannelAsync(this, Discord, options);
/// <inheritdoc />
public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128)
=> CDN.GetUserAvatarUrl(Id, AvatarId, size, format);
/// <inheritdoc />
public string GetDefaultAvatarUrl()
=> CDN.GetDefaultUserAvatarUrl(DiscriminatorValue);
/// <summary>
/// Gets the Username#Discriminator of the user.
/// </summary>
/// <returns>
/// A string that resolves to Username#Discriminator of the user.
/// </returns>
public override string ToString() => $"{Username}#{Discriminator}";
private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")})";
//IUser
/// <inheritdoc />
async Task<IDMChannel> IUser.GetOrCreateDMChannelAsync(RequestOptions options)
=> await GetOrCreateDMChannelAsync(options).ConfigureAwait(false);
}
}