diff --git a/src/Discord.Net/DiscordClient.Messages.cs b/src/Discord.Net/DiscordClient.Messages.cs index 5928f4132..aaf930941 100644 --- a/src/Discord.Net/DiscordClient.Messages.cs +++ b/src/Discord.Net/DiscordClient.Messages.cs @@ -93,7 +93,6 @@ namespace Discord { if (channel == null) throw new ArgumentNullException(nameof(channel)); if (text == null) throw new ArgumentNullException(nameof(text)); - if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); CheckReady(); return SendMessage(channel, text, false); @@ -103,7 +102,6 @@ namespace Discord { if (channel == null) throw new ArgumentNullException(nameof(channel)); if (text == null) throw new ArgumentNullException(nameof(text)); - if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); CheckReady(); return SendMessage(channel, text, false); @@ -113,7 +111,6 @@ namespace Discord { if (user == null) throw new ArgumentNullException(nameof(user)); if (text == null) throw new ArgumentNullException(nameof(text)); - if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); CheckReady(); var channel = await CreatePMChannel(user).ConfigureAwait(false); @@ -122,10 +119,10 @@ namespace Discord private async Task SendMessage(Channel channel, string text, bool isTextToSpeech) { Message msg; - var userIds = !channel.IsPrivate ? Mention.GetUserIds(text).Distinct() : new string[0]; + var server = channel.Server; + if (Config.UseMessageQueue) { - var channelIds = !channel.IsPrivate ? Mention.GetChannelIds(text).Distinct() : new string[0]; var nonce = GenerateNonce(); msg = _messages.GetOrAdd("nonce_" + nonce, channel.Id, _userId); var currentUser = msg.User; @@ -140,21 +137,21 @@ namespace Discord msg.Nonce = nonce; msg.IsQueued = true; - //IsPrivate check is already done earlier - msg.MentionedUsers = userIds - .Select(x => _users[x, channel.Server.Id]) - .Where(x => x != null) - .ToArray(); - msg.MentionedChannels = channelIds - .Select(x => _channels[x]) - .Where(x => x != null && x.Server == channel.Server) - .ToArray(); + if (text.Length > MaxMessageSize) + throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); _pendingMessages.Enqueue(msg); } else { - var model = await _api.SendMessage(channel.Id, text, userIds, null, isTextToSpeech).ConfigureAwait(false); + var mentionedUsers = new List(); + if (!channel.IsPrivate) + text = Mention.CleanUserMentions(this, server, text, mentionedUsers); + + if (text.Length > MaxMessageSize) + throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); + + var model = await _api.SendMessage(channel.Id, text, mentionedUsers.Select(x => x.Id), null, isTextToSpeech).ConfigureAwait(false); msg = _messages.GetOrAdd(model.Id, channel.Id, model.Author.Id); msg.Update(model); RaiseMessageSent(msg); @@ -179,13 +176,17 @@ namespace Discord { if (message == null) throw new ArgumentNullException(nameof(message)); if (text == null) throw new ArgumentNullException(nameof(text)); - if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); CheckReady(); - if (text != null && text.Length > MaxMessageSize) - text = text.Substring(0, MaxMessageSize); + var channel = message.Channel; + var mentionedUsers = new List(); + if (!channel.IsPrivate) + text = Mention.CleanUserMentions(this, channel.Server, text, mentionedUsers); + + if (text.Length > MaxMessageSize) + throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); - return _api.EditMessage(message.Id, message.Channel.Id, text, Mention.GetUserIds(text)); + return _api.EditMessage(message.Id, message.Channel.Id, text, mentionedUsers.Select(x => x.Id)); } /// Deletes the provided message. diff --git a/src/Discord.Net/Helpers/Mention.cs b/src/Discord.Net/Helpers/Mention.cs index f9f44646b..d128e30bd 100644 --- a/src/Discord.Net/Helpers/Mention.cs +++ b/src/Discord.Net/Helpers/Mention.cs @@ -8,6 +8,7 @@ namespace Discord { private static readonly Regex _userRegex = new Regex(@"<@([0-9]+?)>", RegexOptions.Compiled); private static readonly Regex _channelRegex = new Regex(@"<#([0-9]+?)>", RegexOptions.Compiled); + private static readonly Regex _roleRegex = new Regex(@"@everyone", RegexOptions.Compiled); /// Returns the string used to create a user mention. public static string User(User user) @@ -19,45 +20,45 @@ namespace Discord public static string Everyone() => $"@everyone"; - internal static string ConvertToNames(DiscordClient client, Server server, string text) + internal static string CleanUserMentions(DiscordClient client, Server server, string text, List users = null) { - text = _userRegex.Replace(text, new MatchEvaluator(e => + return _userRegex.Replace(text, new MatchEvaluator(e => { string id = e.Value.Substring(2, e.Value.Length - 3); var user = client.Users[id, server?.Id]; if (user != null) + { + if (users != null) + users.Add(user); return '@' + user.Name; + } else //User not found return '@' + e.Value; })); - if (server != null) + } + internal static string CleanChannelMentions(DiscordClient client, Server server, string text, List channels = null) + { + return _channelRegex.Replace(text, new MatchEvaluator(e => { - text = _channelRegex.Replace(text, new MatchEvaluator(e => + string id = e.Value.Substring(2, e.Value.Length - 3); + var channel = client.Channels[id]; + if (channel != null && channel.Server.Id == server.Id) { - string id = e.Value.Substring(2, e.Value.Length - 3); - var channel = client.Channels[id]; - if (channel != null && channel.Server.Id == server.Id) - return '#' + channel.Name; - else //Channel not found + if (channels != null) + channels.Add(channel); + return '#' + channel.Name; + } + else //Channel not found return '#' + e.Value; - })); - } - return text; - } - - internal static IEnumerable GetUserIds(string text) - { - return _userRegex.Matches(text) - .OfType() - .Select(x => x.Groups[1].Value) - .Where(x => x != null); + })); } - internal static IEnumerable GetChannelIds(string text) + internal static string CleanRoleMentions(DiscordClient client, Server server, string text, List roles = null) { - return _channelRegex.Matches(text) - .OfType() - .Select(x => x.Groups[1].Value) - .Where(x => x != null); + return _roleRegex.Replace(text, new MatchEvaluator(e => + { + roles.Add(server.EveryoneRole); + return e.Value; + })); } } } diff --git a/src/Discord.Net/Models/Message.cs b/src/Discord.Net/Models/Message.cs index 5e301758b..30595c683 100644 --- a/src/Discord.Net/Models/Message.cs +++ b/src/Discord.Net/Models/Message.cs @@ -90,9 +90,7 @@ namespace Discord Height = height; } } - - private string _cleanText; - + /// Returns the local unique identifier for this message. public string Nonce { get; internal set; } @@ -110,8 +108,7 @@ namespace Discord /// Returns the raw content of this message as it was received from the server.. public string RawText { get; private set; } /// Returns the content of this message with any special references such as mentions converted. - /// This value is lazy loaded and only processed on first request. Each subsequent request will pull from cache. - public string Text => _cleanText != null ? _cleanText : (_cleanText = Mention.ConvertToNames(_client, Server, RawText)); + public string Text { get; private set; } /// Returns the timestamp for when this message was sent. public DateTime Timestamp { get; private set; } /// Returns the timestamp for when this message was last edited. @@ -131,6 +128,10 @@ namespace Discord [JsonIgnore] public IEnumerable MentionedChannels { get; internal set; } + /// Returns a collection of all roles mentioned in this message. + [JsonIgnore] + public IEnumerable MentionedRoles { get; internal set; } + /// Returns the server containing the channel this message was sent to. [JsonIgnore] public Server Server => _channel.Value.Server; @@ -220,18 +221,23 @@ namespace Discord } if (model.Content != null) { - RawText = model.Content; - _cleanText = null; - - if (!Channel.IsPrivate) + var server = Server; + string text = model.Content; + RawText = text; + + //var mentionedUsers = new List(); + var mentionedChannels = new List(); + var mentionedRoles = new List(); + text = Mention.CleanUserMentions(_client, server, text/*, mentionedUsers*/); + if (server != null) { - MentionedChannels = Mention.GetChannelIds(model.Content) - .Select(x => _client.Channels[x]) - .Where(x => x.Server == Channel.Server) - .ToArray(); + text = Mention.CleanChannelMentions(_client, server, text, mentionedChannels); + text = Mention.CleanRoleMentions(_client, server, text, mentionedRoles); } - else - MentionedChannels = new Channel[0]; + + //MentionedUsers = mentionedUsers; + MentionedChannels = mentionedChannels; + MentionedRoles = mentionedRoles; } }