Fixed several message parsing issues, added optional deserialization
This commit is contained in:
@@ -13,8 +13,8 @@ namespace Discord.API
|
||||
[JsonProperty("url")]
|
||||
public string Url { get; set; }
|
||||
[JsonProperty("thumbnail")]
|
||||
public EmbedThumbnail Thumbnail { get; set; }
|
||||
public Optional<EmbedThumbnail> Thumbnail { get; set; }
|
||||
[JsonProperty("provider")]
|
||||
public EmbedProvider Provider { get; set; }
|
||||
public Optional<EmbedProvider> Provider { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,24 +10,22 @@ namespace Discord.API
|
||||
[JsonProperty("channel_id")]
|
||||
public ulong ChannelId { get; set; }
|
||||
[JsonProperty("author")]
|
||||
public User Author { get; set; }
|
||||
public Optional<User> Author { get; set; }
|
||||
[JsonProperty("content")]
|
||||
public string Content { get; set; }
|
||||
public Optional<string> Content { get; set; }
|
||||
[JsonProperty("timestamp")]
|
||||
public DateTime Timestamp { get; set; }
|
||||
public Optional<DateTime> Timestamp { get; set; }
|
||||
[JsonProperty("edited_timestamp")]
|
||||
public DateTime? EditedTimestamp { get; set; }
|
||||
public Optional<DateTime?> EditedTimestamp { get; set; }
|
||||
[JsonProperty("tts")]
|
||||
public bool IsTextToSpeech { get; set; }
|
||||
public Optional<bool> IsTextToSpeech { get; set; }
|
||||
[JsonProperty("mention_everyone")]
|
||||
public bool IsMentioningEveryone { get; set; }
|
||||
public Optional<bool> IsMentioningEveryone { get; set; }
|
||||
[JsonProperty("mentions")]
|
||||
public User[] Mentions { get; set; }
|
||||
public Optional<User[]> Mentions { get; set; }
|
||||
[JsonProperty("attachments")]
|
||||
public Attachment[] Attachments { get; set; }
|
||||
public Optional<Attachment[]> Attachments { get; set; }
|
||||
[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;
|
||||
if (channel != null)
|
||||
{
|
||||
var author = channel.GetUser(data.Author.Id);
|
||||
var author = channel.GetUser(data.Author.Value.Id);
|
||||
|
||||
if (author != null)
|
||||
{
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Discord
|
||||
{
|
||||
var args = new CreateMessageParams { Content = text, IsTTS = isTTS };
|
||||
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)
|
||||
{
|
||||
@@ -79,33 +79,33 @@ namespace Discord
|
||||
{
|
||||
var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS };
|
||||
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)
|
||||
{
|
||||
var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS };
|
||||
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)
|
||||
{
|
||||
var model = await Discord.ApiClient.GetChannelMessageAsync(Id, id).ConfigureAwait(false);
|
||||
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;
|
||||
}
|
||||
public virtual async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit)
|
||||
{
|
||||
var args = new GetChannelMessagesParams { Limit = limit };
|
||||
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)
|
||||
{
|
||||
var args = new GetChannelMessagesParams { Limit = limit };
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Discord
|
||||
{
|
||||
var args = new CreateMessageParams { Content = text, IsTTS = isTTS };
|
||||
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)
|
||||
{
|
||||
@@ -71,33 +71,33 @@ namespace Discord
|
||||
{
|
||||
var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS };
|
||||
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)
|
||||
{
|
||||
var args = new UploadFileParams { Filename = filename, Content = text, IsTTS = isTTS };
|
||||
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)
|
||||
{
|
||||
var model = await Discord.ApiClient.GetChannelMessageAsync(Id, id).ConfigureAwait(false);
|
||||
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;
|
||||
}
|
||||
public virtual async Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit)
|
||||
{
|
||||
var args = new GetChannelMessagesParams { Limit = limit };
|
||||
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)
|
||||
{
|
||||
var args = new GetChannelMessagesParams { Limit = limit };
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -18,8 +18,10 @@ namespace Discord
|
||||
Title = model.Title;
|
||||
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}")]
|
||||
internal class Message : SnowflakeEntity, IMessage
|
||||
{
|
||||
{
|
||||
private bool _isMentioningEveryone;
|
||||
|
||||
public DateTime? EditedTimestamp { get; private set; }
|
||||
public bool IsTTS { get; private set; }
|
||||
public string RawText { get; private set; }
|
||||
@@ -34,6 +36,13 @@ namespace Discord
|
||||
Channel = channel;
|
||||
Author = author;
|
||||
|
||||
if (channel is IGuildChannel)
|
||||
{
|
||||
MentionedUsers = ImmutableArray.Create<User>();
|
||||
MentionedChannelIds = ImmutableArray.Create<ulong>();
|
||||
MentionedRoleIds = ImmutableArray.Create<ulong>();
|
||||
}
|
||||
|
||||
Update(model, UpdateSource.Creation);
|
||||
}
|
||||
public void Update(Model model, UpdateSource source)
|
||||
@@ -44,57 +53,73 @@ namespace Discord
|
||||
var guild = guildChannel?.Guild;
|
||||
var discord = Discord;
|
||||
|
||||
IsTTS = model.IsTextToSpeech;
|
||||
Timestamp = model.Timestamp;
|
||||
EditedTimestamp = model.EditedTimestamp;
|
||||
RawText = model.Content;
|
||||
|
||||
if (model.Attachments.Length > 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
Attachments = ImmutableArray.Create<Attachment>();
|
||||
|
||||
if (model.Embeds.Length > 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
Embeds = ImmutableArray.Create<Embed>();
|
||||
|
||||
if (guildChannel != null && model.Mentions.Length > 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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
|
||||
{
|
||||
MentionedChannelIds = ImmutableArray.Create<ulong>();
|
||||
MentionedRoleIds = ImmutableArray.Create<ulong>();
|
||||
}
|
||||
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;
|
||||
|
||||
Text = MentionUtils.CleanUserMentions(model.Content, model.Mentions);
|
||||
if (model.Attachments.IsSpecified)
|
||||
{
|
||||
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>();
|
||||
}
|
||||
|
||||
if (model.Embeds.IsSpecified)
|
||||
{
|
||||
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>();
|
||||
}
|
||||
|
||||
if (model.Mentions.IsSpecified)
|
||||
{
|
||||
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>();
|
||||
}
|
||||
|
||||
if (model.Content.IsSpecified)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateAsync()
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace Discord.Net.Converters
|
||||
converter = ImageConverter.Instance;
|
||||
else if (type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(Optional<>))
|
||||
{
|
||||
var innerType = type.GenericTypeArguments[0];
|
||||
var typeInput = propInfo.DeclaringType;
|
||||
var typeOutput = propInfo.PropertyType;
|
||||
|
||||
@@ -62,9 +63,10 @@ namespace Discord.Net.Converters
|
||||
var getterDelegate = propInfo.GetMethod.CreateDelegate(getter);
|
||||
var shouldSerialize = _shouldSerialize.MakeGenericMethod(typeInput, typeOutput);
|
||||
var shouldSerializeDelegate = (Func<object, Delegate, bool>)shouldSerialize.CreateDelegate(typeof(Func<object, Delegate, bool>));
|
||||
|
||||
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
|
||||
{
|
||||
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 CanRead => false;
|
||||
public override bool CanRead => true;
|
||||
public override bool CanWrite => true;
|
||||
|
||||
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)
|
||||
{
|
||||
serializer.Serialize(writer, (value as IOptional).Value);
|
||||
serializer.Serialize(writer, ((Optional<T>)value).Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace Discord
|
||||
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 =>
|
||||
{
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace Discord
|
||||
return msg;
|
||||
var model = await _discord.ApiClient.GetChannelMessageAsync(_channel.Id, id).ConfigureAwait(false);
|
||||
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;
|
||||
}
|
||||
public async Task<IReadOnlyCollection<CachedMessage>> DownloadAsync(ulong? fromId, Direction dir, int limit)
|
||||
|
||||
Reference in New Issue
Block a user