Browse Source

Fixed several message parsing issues, added optional deserialization

tags/1.0-rc
RogueException 9 years ago
parent
commit
cc5e0bbe13
11 changed files with 105 additions and 78 deletions
  1. +2
    -2
      src/Discord.Net/API/Common/Embed.cs
  2. +9
    -11
      src/Discord.Net/API/Common/Message.cs
  3. +1
    -1
      src/Discord.Net/DiscordSocketClient.cs
  4. +6
    -6
      src/Discord.Net/Entities/Channels/DMChannel.cs
  5. +6
    -6
      src/Discord.Net/Entities/Channels/TextChannel.cs
  6. +4
    -2
      src/Discord.Net/Entities/Messages/Embed.cs
  7. +66
    -41
      src/Discord.Net/Entities/Messages/Message.cs
  8. +4
    -2
      src/Discord.Net/Net/Converters/DiscordContractResolver.cs
  9. +5
    -5
      src/Discord.Net/Net/Converters/OptionalConverter.cs
  10. +1
    -1
      src/Discord.Net/Utilities/MentionUtils.cs
  11. +1
    -1
      src/Discord.Net/Utilities/MessageCache.cs

+ 2
- 2
src/Discord.Net/API/Common/Embed.cs View File

@@ -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; }
} }
} }

+ 9
- 11
src/Discord.Net/API/Common/Message.cs View File

@@ -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; }
} }
} }

+ 1
- 1
src/Discord.Net/DiscordSocketClient.cs View File

@@ -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)
{ {


+ 6
- 6
src/Discord.Net/Entities/Channels/DMChannel.cs View File

@@ -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)
{ {


+ 6
- 6
src/Discord.Net/Entities/Channels/TextChannel.cs View File

@@ -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)
{ {


+ 4
- 2
src/Discord.Net/Entities/Messages/Embed.cs View File

@@ -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);
} }
} }
} }

+ 66
- 41
src/Discord.Net/Entities/Messages/Message.cs View File

@@ -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()


+ 4
- 2
src/Discord.Net/Net/Converters/DiscordContractResolver.cs View File

@@ -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;
} }
} }




+ 5
- 5
src/Discord.Net/Net/Converters/OptionalConverter.cs View File

@@ -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);
} }
} }
} }

+ 1
- 1
src/Discord.Net/Utilities/MentionUtils.cs View File

@@ -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 =>
{ {


+ 1
- 1
src/Discord.Net/Utilities/MessageCache.cs View File

@@ -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)


Loading…
Cancel
Save