| @@ -13,8 +13,8 @@ namespace Discord.API | |||||
| [JsonProperty("url")] | [JsonProperty("url")] | ||||
| public string Url { get; set; } | public string Url { get; set; } | ||||
| [JsonProperty("thumbnail")] | [JsonProperty("thumbnail")] | ||||
| public EmbedThumbnail Thumbnail { get; set; } | |||||
| public Optional<EmbedThumbnail> Thumbnail { get; set; } | |||||
| [JsonProperty("provider")] | [JsonProperty("provider")] | ||||
| public EmbedProvider Provider { get; set; } | |||||
| public Optional<EmbedProvider> Provider { get; set; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -10,24 +10,22 @@ namespace Discord.API | |||||
| [JsonProperty("channel_id")] | [JsonProperty("channel_id")] | ||||
| public ulong ChannelId { get; set; } | public ulong ChannelId { get; set; } | ||||
| [JsonProperty("author")] | [JsonProperty("author")] | ||||
| public User Author { get; set; } | |||||
| public Optional<User> Author { get; set; } | |||||
| [JsonProperty("content")] | [JsonProperty("content")] | ||||
| public string Content { get; set; } | |||||
| public Optional<string> Content { get; set; } | |||||
| [JsonProperty("timestamp")] | [JsonProperty("timestamp")] | ||||
| public DateTime Timestamp { get; set; } | |||||
| public Optional<DateTime> Timestamp { get; set; } | |||||
| [JsonProperty("edited_timestamp")] | [JsonProperty("edited_timestamp")] | ||||
| public DateTime? EditedTimestamp { get; set; } | |||||
| public Optional<DateTime?> EditedTimestamp { get; set; } | |||||
| [JsonProperty("tts")] | [JsonProperty("tts")] | ||||
| public bool IsTextToSpeech { get; set; } | |||||
| public Optional<bool> IsTextToSpeech { get; set; } | |||||
| [JsonProperty("mention_everyone")] | [JsonProperty("mention_everyone")] | ||||
| public bool IsMentioningEveryone { get; set; } | |||||
| public Optional<bool> IsMentioningEveryone { get; set; } | |||||
| [JsonProperty("mentions")] | [JsonProperty("mentions")] | ||||
| public User[] Mentions { get; set; } | |||||
| public Optional<User[]> Mentions { get; set; } | |||||
| [JsonProperty("attachments")] | [JsonProperty("attachments")] | ||||
| public Attachment[] Attachments { get; set; } | |||||
| public Optional<Attachment[]> Attachments { get; set; } | |||||
| [JsonProperty("embeds")] | [JsonProperty("embeds")] | ||||
| public Embed[] Embeds { get; set; } | |||||
| /*[JsonProperty("nonce")] | |||||
| public object Nonce { get; set; }*/ | |||||
| public Optional<Embed[]> Embeds { get; set; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -729,7 +729,7 @@ namespace Discord | |||||
| var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; | var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; | ||||
| if (channel != null) | if (channel != null) | ||||
| { | { | ||||
| var author = channel.GetUser(data.Author.Id); | |||||
| var author = channel.GetUser(data.Author.Value.Id); | |||||
| if (author != null) | if (author != null) | ||||
| { | { | ||||
| @@ -70,7 +70,7 @@ namespace Discord | |||||
| { | { | ||||
| var args = new CreateMessageParams { Content = text, IsTTS = isTTS }; | var args = new CreateMessageParams { Content = text, IsTTS = isTTS }; | ||||
| var model = await Discord.ApiClient.CreateDMMessageAsync(Id, args).ConfigureAwait(false); | var model = await Discord.ApiClient.CreateDMMessageAsync(Id, args).ConfigureAwait(false); | ||||
| return new Message(this, new User(Discord, model.Author), model); | |||||
| return new Message(this, new User(Discord, model.Author.Value), model); | |||||
| } | } | ||||
| public async Task<IMessage> SendFileAsync(string filePath, string text, bool isTTS) | public async Task<IMessage> SendFileAsync(string filePath, string text, bool isTTS) | ||||
| { | { | ||||
| @@ -79,33 +79,33 @@ namespace Discord | |||||
| { | { | ||||
| var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS }; | var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS }; | ||||
| var model = await Discord.ApiClient.UploadDMFileAsync(Id, file, args).ConfigureAwait(false); | var model = await Discord.ApiClient.UploadDMFileAsync(Id, file, args).ConfigureAwait(false); | ||||
| return new Message(this, new User(Discord, model.Author), model); | |||||
| return new Message(this, new User(Discord, model.Author.Value), model); | |||||
| } | } | ||||
| } | } | ||||
| public async Task<IMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS) | public async Task<IMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS) | ||||
| { | { | ||||
| var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS }; | var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS }; | ||||
| var model = await Discord.ApiClient.UploadDMFileAsync(Id, stream, args).ConfigureAwait(false); | var model = await Discord.ApiClient.UploadDMFileAsync(Id, stream, args).ConfigureAwait(false); | ||||
| return new Message(this, new User(Discord, model.Author), model); | |||||
| return new Message(this, new User(Discord, model.Author.Value), model); | |||||
| } | } | ||||
| public virtual async Task<IMessage> GetMessageAsync(ulong id) | public virtual async Task<IMessage> GetMessageAsync(ulong id) | ||||
| { | { | ||||
| var model = await Discord.ApiClient.GetChannelMessageAsync(Id, id).ConfigureAwait(false); | var model = await Discord.ApiClient.GetChannelMessageAsync(Id, id).ConfigureAwait(false); | ||||
| if (model != null) | if (model != null) | ||||
| return new Message(this, new User(Discord, model.Author), model); | |||||
| return new Message(this, new User(Discord, model.Author.Value), model); | |||||
| return null; | return null; | ||||
| } | } | ||||
| public virtual async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit) | public virtual async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit) | ||||
| { | { | ||||
| var args = new GetChannelMessagesParams { Limit = limit }; | var args = new GetChannelMessagesParams { Limit = limit }; | ||||
| var models = await Discord.ApiClient.GetChannelMessagesAsync(Id, args).ConfigureAwait(false); | var models = await Discord.ApiClient.GetChannelMessagesAsync(Id, args).ConfigureAwait(false); | ||||
| return models.Select(x => new Message(this, new User(Discord, x.Author), x)).ToImmutableArray(); | |||||
| return models.Select(x => new Message(this, new User(Discord, x.Author.Value), x)).ToImmutableArray(); | |||||
| } | } | ||||
| public virtual async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit) | public virtual async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit) | ||||
| { | { | ||||
| var args = new GetChannelMessagesParams { Limit = limit }; | var args = new GetChannelMessagesParams { Limit = limit }; | ||||
| var models = await Discord.ApiClient.GetChannelMessagesAsync(Id, args).ConfigureAwait(false); | var models = await Discord.ApiClient.GetChannelMessagesAsync(Id, args).ConfigureAwait(false); | ||||
| return models.Select(x => new Message(this, new User(Discord, x.Author), x)).ToImmutableArray(); | |||||
| return models.Select(x => new Message(this, new User(Discord, x.Author.Value), x)).ToImmutableArray(); | |||||
| } | } | ||||
| public async Task DeleteMessagesAsync(IEnumerable<IMessage> messages) | public async Task DeleteMessagesAsync(IEnumerable<IMessage> messages) | ||||
| { | { | ||||
| @@ -62,7 +62,7 @@ namespace Discord | |||||
| { | { | ||||
| var args = new CreateMessageParams { Content = text, IsTTS = isTTS }; | var args = new CreateMessageParams { Content = text, IsTTS = isTTS }; | ||||
| var model = await Discord.ApiClient.CreateMessageAsync(Guild.Id, Id, args).ConfigureAwait(false); | var model = await Discord.ApiClient.CreateMessageAsync(Guild.Id, Id, args).ConfigureAwait(false); | ||||
| return new Message(this, new User(Discord, model.Author), model); | |||||
| return new Message(this, new User(Discord, model.Author.Value), model); | |||||
| } | } | ||||
| public async Task<IMessage> SendFileAsync(string filePath, string text, bool isTTS) | public async Task<IMessage> SendFileAsync(string filePath, string text, bool isTTS) | ||||
| { | { | ||||
| @@ -71,33 +71,33 @@ namespace Discord | |||||
| { | { | ||||
| var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS }; | var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS }; | ||||
| var model = await Discord.ApiClient.UploadFileAsync(Guild.Id, Id, file, args).ConfigureAwait(false); | var model = await Discord.ApiClient.UploadFileAsync(Guild.Id, Id, file, args).ConfigureAwait(false); | ||||
| return new Message(this, new User(Discord, model.Author), model); | |||||
| return new Message(this, new User(Discord, model.Author.Value), model); | |||||
| } | } | ||||
| } | } | ||||
| public async Task<IMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS) | public async Task<IMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS) | ||||
| { | { | ||||
| var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS }; | var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS }; | ||||
| var model = await Discord.ApiClient.UploadFileAsync(Guild.Id, Id, stream, args).ConfigureAwait(false); | var model = await Discord.ApiClient.UploadFileAsync(Guild.Id, Id, stream, args).ConfigureAwait(false); | ||||
| return new Message(this, new User(Discord, model.Author), model); | |||||
| return new Message(this, new User(Discord, model.Author.Value), model); | |||||
| } | } | ||||
| public virtual async Task<IMessage> GetMessageAsync(ulong id) | public virtual async Task<IMessage> GetMessageAsync(ulong id) | ||||
| { | { | ||||
| var model = await Discord.ApiClient.GetChannelMessageAsync(Id, id).ConfigureAwait(false); | var model = await Discord.ApiClient.GetChannelMessageAsync(Id, id).ConfigureAwait(false); | ||||
| if (model != null) | if (model != null) | ||||
| return new Message(this, new User(Discord, model.Author), model); | |||||
| return new Message(this, new User(Discord, model.Author.Value), model); | |||||
| return null; | return null; | ||||
| } | } | ||||
| public virtual async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit) | public virtual async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit) | ||||
| { | { | ||||
| var args = new GetChannelMessagesParams { Limit = limit }; | var args = new GetChannelMessagesParams { Limit = limit }; | ||||
| var models = await Discord.ApiClient.GetChannelMessagesAsync(Id, args).ConfigureAwait(false); | var models = await Discord.ApiClient.GetChannelMessagesAsync(Id, args).ConfigureAwait(false); | ||||
| return models.Select(x => new Message(this, new User(Discord, x.Author), x)).ToImmutableArray(); | |||||
| return models.Select(x => new Message(this, new User(Discord, x.Author.Value), x)).ToImmutableArray(); | |||||
| } | } | ||||
| public virtual async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit) | public virtual async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit) | ||||
| { | { | ||||
| var args = new GetChannelMessagesParams { Limit = limit }; | var args = new GetChannelMessagesParams { Limit = limit }; | ||||
| var models = await Discord.ApiClient.GetChannelMessagesAsync(Id, args).ConfigureAwait(false); | var models = await Discord.ApiClient.GetChannelMessagesAsync(Id, args).ConfigureAwait(false); | ||||
| return models.Select(x => new Message(this, new User(Discord, x.Author), x)).ToImmutableArray(); | |||||
| return models.Select(x => new Message(this, new User(Discord, x.Author.Value), x)).ToImmutableArray(); | |||||
| } | } | ||||
| public async Task DeleteMessagesAsync(IEnumerable<IMessage> messages) | public async Task DeleteMessagesAsync(IEnumerable<IMessage> messages) | ||||
| { | { | ||||
| @@ -18,8 +18,10 @@ namespace Discord | |||||
| Title = model.Title; | Title = model.Title; | ||||
| Description = model.Description; | Description = model.Description; | ||||
| Provider = new EmbedProvider(model.Provider); | |||||
| Thumbnail = new EmbedThumbnail(model.Thumbnail); | |||||
| if (model.Provider.IsSpecified) | |||||
| Provider = new EmbedProvider(model.Provider.Value); | |||||
| if (model.Thumbnail.IsSpecified) | |||||
| Thumbnail = new EmbedThumbnail(model.Thumbnail.Value); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -10,7 +10,9 @@ namespace Discord | |||||
| { | { | ||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
| internal class Message : SnowflakeEntity, IMessage | internal class Message : SnowflakeEntity, IMessage | ||||
| { | |||||
| { | |||||
| private bool _isMentioningEveryone; | |||||
| public DateTime? EditedTimestamp { get; private set; } | public DateTime? EditedTimestamp { get; private set; } | ||||
| public bool IsTTS { get; private set; } | public bool IsTTS { get; private set; } | ||||
| public string RawText { get; private set; } | public string RawText { get; private set; } | ||||
| @@ -34,6 +36,13 @@ namespace Discord | |||||
| Channel = channel; | Channel = channel; | ||||
| Author = author; | Author = author; | ||||
| if (channel is IGuildChannel) | |||||
| { | |||||
| MentionedUsers = ImmutableArray.Create<User>(); | |||||
| MentionedChannelIds = ImmutableArray.Create<ulong>(); | |||||
| MentionedRoleIds = ImmutableArray.Create<ulong>(); | |||||
| } | |||||
| Update(model, UpdateSource.Creation); | Update(model, UpdateSource.Creation); | ||||
| } | } | ||||
| public void Update(Model model, UpdateSource source) | public void Update(Model model, UpdateSource source) | ||||
| @@ -44,57 +53,73 @@ namespace Discord | |||||
| var guild = guildChannel?.Guild; | var guild = guildChannel?.Guild; | ||||
| var discord = Discord; | var discord = Discord; | ||||
| IsTTS = model.IsTextToSpeech; | |||||
| Timestamp = model.Timestamp; | |||||
| EditedTimestamp = model.EditedTimestamp; | |||||
| RawText = model.Content; | |||||
| if (model.Attachments.Length > 0) | |||||
| if (model.IsTextToSpeech.IsSpecified) | |||||
| IsTTS = model.IsTextToSpeech.Value; | |||||
| if (model.Timestamp.IsSpecified) | |||||
| Timestamp = model.Timestamp.Value; | |||||
| if (model.EditedTimestamp.IsSpecified) | |||||
| EditedTimestamp = model.EditedTimestamp.Value; | |||||
| if (model.IsMentioningEveryone.IsSpecified) | |||||
| _isMentioningEveryone = model.IsMentioningEveryone.Value; | |||||
| if (model.Attachments.IsSpecified) | |||||
| { | { | ||||
| var attachments = new Attachment[model.Attachments.Length]; | |||||
| for (int i = 0; i < attachments.Length; i++) | |||||
| attachments[i] = new Attachment(model.Attachments[i]); | |||||
| Attachments = ImmutableArray.Create(attachments); | |||||
| var value = model.Attachments.Value; | |||||
| if (value.Length > 0) | |||||
| { | |||||
| var attachments = new Attachment[value.Length]; | |||||
| for (int i = 0; i < attachments.Length; i++) | |||||
| attachments[i] = new Attachment(value[i]); | |||||
| Attachments = ImmutableArray.Create(attachments); | |||||
| } | |||||
| else | |||||
| Attachments = ImmutableArray.Create<Attachment>(); | |||||
| } | } | ||||
| else | |||||
| Attachments = ImmutableArray.Create<Attachment>(); | |||||
| if (model.Embeds.Length > 0) | |||||
| if (model.Embeds.IsSpecified) | |||||
| { | { | ||||
| var embeds = new Embed[model.Attachments.Length]; | |||||
| for (int i = 0; i < embeds.Length; i++) | |||||
| embeds[i] = new Embed(model.Embeds[i]); | |||||
| Embeds = ImmutableArray.Create(embeds); | |||||
| var value = model.Embeds.Value; | |||||
| if (value.Length > 0) | |||||
| { | |||||
| var embeds = new Embed[value.Length]; | |||||
| for (int i = 0; i < embeds.Length; i++) | |||||
| embeds[i] = new Embed(value[i]); | |||||
| Embeds = ImmutableArray.Create(embeds); | |||||
| } | |||||
| else | |||||
| Embeds = ImmutableArray.Create<Embed>(); | |||||
| } | } | ||||
| else | |||||
| Embeds = ImmutableArray.Create<Embed>(); | |||||
| if (guildChannel != null && model.Mentions.Length > 0) | |||||
| if (model.Mentions.IsSpecified) | |||||
| { | { | ||||
| var mentions = new User[model.Mentions.Length]; | |||||
| for (int i = 0; i < model.Mentions.Length; i++) | |||||
| mentions[i] = new User(discord, model.Mentions[i]); | |||||
| MentionedUsers = ImmutableArray.Create(mentions); | |||||
| var value = model.Mentions.Value; | |||||
| if (value.Length > 0) | |||||
| { | |||||
| var mentions = new User[value.Length]; | |||||
| for (int i = 0; i < value.Length; i++) | |||||
| mentions[i] = new User(discord, value[i]); | |||||
| MentionedUsers = ImmutableArray.Create(mentions); | |||||
| } | |||||
| else | |||||
| MentionedUsers = ImmutableArray.Create<User>(); | |||||
| } | } | ||||
| else | |||||
| MentionedUsers = ImmutableArray.Create<User>(); | |||||
| if (guildChannel != null) | |||||
| { | |||||
| MentionedChannelIds = MentionUtils.GetChannelMentions(model.Content); | |||||
| var mentionedRoleIds = MentionUtils.GetRoleMentions(model.Content); | |||||
| if (model.IsMentioningEveryone) | |||||
| mentionedRoleIds = mentionedRoleIds.Add(guildChannel.Guild.EveryoneRole.Id); | |||||
| MentionedRoleIds = mentionedRoleIds; | |||||
| } | |||||
| else | |||||
| if (model.Content.IsSpecified) | |||||
| { | { | ||||
| MentionedChannelIds = ImmutableArray.Create<ulong>(); | |||||
| MentionedRoleIds = ImmutableArray.Create<ulong>(); | |||||
| RawText = model.Content.Value; | |||||
| if (Channel is IGuildChannel) | |||||
| { | |||||
| Text = MentionUtils.CleanUserMentions(RawText, MentionedUsers); | |||||
| MentionedChannelIds = MentionUtils.GetChannelMentions(RawText); | |||||
| var mentionedRoleIds = MentionUtils.GetRoleMentions(RawText); | |||||
| if (_isMentioningEveryone) | |||||
| mentionedRoleIds = mentionedRoleIds.Add(guildChannel.Guild.EveryoneRole.Id); | |||||
| MentionedRoleIds = mentionedRoleIds; | |||||
| } | |||||
| else | |||||
| Text = RawText; | |||||
| } | } | ||||
| Text = MentionUtils.CleanUserMentions(model.Content, model.Mentions); | |||||
| } | } | ||||
| public async Task UpdateAsync() | public async Task UpdateAsync() | ||||
| @@ -55,6 +55,7 @@ namespace Discord.Net.Converters | |||||
| converter = ImageConverter.Instance; | converter = ImageConverter.Instance; | ||||
| else if (type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(Optional<>)) | else if (type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(Optional<>)) | ||||
| { | { | ||||
| var innerType = type.GenericTypeArguments[0]; | |||||
| var typeInput = propInfo.DeclaringType; | var typeInput = propInfo.DeclaringType; | ||||
| var typeOutput = propInfo.PropertyType; | var typeOutput = propInfo.PropertyType; | ||||
| @@ -62,9 +63,10 @@ namespace Discord.Net.Converters | |||||
| var getterDelegate = propInfo.GetMethod.CreateDelegate(getter); | var getterDelegate = propInfo.GetMethod.CreateDelegate(getter); | ||||
| var shouldSerialize = _shouldSerialize.MakeGenericMethod(typeInput, typeOutput); | var shouldSerialize = _shouldSerialize.MakeGenericMethod(typeInput, typeOutput); | ||||
| var shouldSerializeDelegate = (Func<object, Delegate, bool>)shouldSerialize.CreateDelegate(typeof(Func<object, Delegate, bool>)); | var shouldSerializeDelegate = (Func<object, Delegate, bool>)shouldSerialize.CreateDelegate(typeof(Func<object, Delegate, bool>)); | ||||
| property.ShouldSerialize = x => shouldSerializeDelegate(x, getterDelegate); | property.ShouldSerialize = x => shouldSerializeDelegate(x, getterDelegate); | ||||
| converter = OptionalConverter.Instance; | |||||
| var converterType = typeof(OptionalConverter<>).MakeGenericType(innerType); | |||||
| converter = converterType.GetTypeInfo().GetDeclaredField("Instance").GetValue(null) as JsonConverter; | |||||
| } | } | ||||
| } | } | ||||
| @@ -3,22 +3,22 @@ using System; | |||||
| namespace Discord.Net.Converters | namespace Discord.Net.Converters | ||||
| { | { | ||||
| public class OptionalConverter : JsonConverter | |||||
| public class OptionalConverter<T> : JsonConverter | |||||
| { | { | ||||
| public static readonly OptionalConverter Instance = new OptionalConverter(); | |||||
| public static readonly OptionalConverter<T> Instance = new OptionalConverter<T>(); | |||||
| public override bool CanConvert(Type objectType) => true; | public override bool CanConvert(Type objectType) => true; | ||||
| public override bool CanRead => false; | |||||
| public override bool CanRead => true; | |||||
| public override bool CanWrite => true; | public override bool CanWrite => true; | ||||
| public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) | ||||
| { | { | ||||
| throw new InvalidOperationException(); | |||||
| return new Optional<T>(serializer.Deserialize<T>(reader)); | |||||
| } | } | ||||
| public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) | ||||
| { | { | ||||
| serializer.Serialize(writer, (value as IOptional).Value); | |||||
| serializer.Serialize(writer, ((Optional<T>)value).Value); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -82,7 +82,7 @@ namespace Discord | |||||
| return builder; | return builder; | ||||
| } | } | ||||
| internal static string CleanUserMentions(string text, API.User[] mentions) | |||||
| internal static string CleanUserMentions(string text, ImmutableArray<User> mentions) | |||||
| { | { | ||||
| return _userRegex.Replace(text, new MatchEvaluator(e => | return _userRegex.Replace(text, new MatchEvaluator(e => | ||||
| { | { | ||||
| @@ -88,7 +88,7 @@ namespace Discord | |||||
| return msg; | return msg; | ||||
| var model = await _discord.ApiClient.GetChannelMessageAsync(_channel.Id, id).ConfigureAwait(false); | var model = await _discord.ApiClient.GetChannelMessageAsync(_channel.Id, id).ConfigureAwait(false); | ||||
| if (model != null) | if (model != null) | ||||
| return new CachedMessage(_channel, new User(_discord, model.Author), model); | |||||
| return new CachedMessage(_channel, new User(_discord, model.Author.Value), model); | |||||
| return null; | return null; | ||||
| } | } | ||||
| public async Task<IReadOnlyCollection<CachedMessage>> DownloadAsync(ulong? fromId, Direction dir, int limit) | public async Task<IReadOnlyCollection<CachedMessage>> DownloadAsync(ulong? fromId, Direction dir, int limit) | ||||