Browse Source

Split IMessage into IUserMessage and ISystemMessage

tags/1.0-rc
RogueException 8 years ago
parent
commit
23a0316252
36 changed files with 464 additions and 242 deletions
  1. +1
    -1
      src/Discord.Net.Commands/Attributes/PreconditionAttribute.cs
  2. +1
    -1
      src/Discord.Net.Commands/Attributes/Preconditions/RequireContextAttribute.cs
  3. +1
    -1
      src/Discord.Net.Commands/Attributes/Preconditions/RequirePermissionAttribute.cs
  4. +11
    -11
      src/Discord.Net.Commands/Command.cs
  5. +1
    -1
      src/Discord.Net.Commands/CommandParameter.cs
  6. +1
    -1
      src/Discord.Net.Commands/CommandParser.cs
  7. +7
    -6
      src/Discord.Net.Commands/CommandService.cs
  8. +3
    -3
      src/Discord.Net.Commands/Extensions/MessageExtensions.cs
  9. +1
    -1
      src/Discord.Net.Commands/Readers/ChannelTypeReader.cs
  10. +1
    -1
      src/Discord.Net.Commands/Readers/EnumTypeReader.cs
  11. +4
    -3
      src/Discord.Net.Commands/Readers/MessageTypeReader.cs
  12. +1
    -1
      src/Discord.Net.Commands/Readers/RoleTypeReader.cs
  13. +1
    -1
      src/Discord.Net.Commands/Readers/SimpleTypeReader.cs
  14. +1
    -1
      src/Discord.Net.Commands/Readers/TypeReader.cs
  15. +1
    -1
      src/Discord.Net.Commands/Readers/UserTypeReader.cs
  16. +0
    -2
      src/Discord.Net/API/Rest/GetChannelMessagesParams.cs
  17. +3
    -3
      src/Discord.Net/Entities/Channels/IMessageChannel.cs
  18. +5
    -28
      src/Discord.Net/Entities/Messages/IMessage.cs
  19. +8
    -0
      src/Discord.Net/Entities/Messages/ISystemMessage.cs
  20. +29
    -0
      src/Discord.Net/Entities/Messages/IUserMessage.cs
  21. +25
    -12
      src/Discord.Net/Rest/Entities/Channels/DMChannel.cs
  22. +23
    -10
      src/Discord.Net/Rest/Entities/Channels/GroupChannel.cs
  23. +23
    -10
      src/Discord.Net/Rest/Entities/Channels/TextChannel.cs
  24. +15
    -98
      src/Discord.Net/Rest/Entities/Messages/Message.cs
  25. +22
    -0
      src/Discord.Net/Rest/Entities/Messages/SystemMessage.cs
  26. +175
    -0
      src/Discord.Net/Rest/Entities/Messages/UserMessage.cs
  27. +2
    -2
      src/Discord.Net/WebSocket/DiscordSocketClient.cs
  28. +4
    -3
      src/Discord.Net/WebSocket/Entities/Channels/ISocketMessageChannel.cs
  29. +13
    -13
      src/Discord.Net/WebSocket/Entities/Channels/MessageCache.cs
  30. +21
    -12
      src/Discord.Net/WebSocket/Entities/Channels/MessageManager.cs
  31. +8
    -4
      src/Discord.Net/WebSocket/Entities/Channels/SocketDMChannel.cs
  32. +8
    -4
      src/Discord.Net/WebSocket/Entities/Channels/SocketGroupChannel.cs
  33. +8
    -4
      src/Discord.Net/WebSocket/Entities/Channels/SocketTextChannel.cs
  34. +13
    -0
      src/Discord.Net/WebSocket/Entities/Messages/ISocketMessage.cs
  35. +20
    -0
      src/Discord.Net/WebSocket/Entities/Messages/SocketSystemMessage.cs
  36. +3
    -3
      src/Discord.Net/WebSocket/Entities/Messages/SocketUserMessage.cs

+ 1
- 1
src/Discord.Net.Commands/Attributes/PreconditionAttribute.cs View File

@@ -6,6 +6,6 @@ namespace Discord.Commands
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = true)] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public abstract class PreconditionAttribute : Attribute public abstract class PreconditionAttribute : Attribute
{ {
public abstract Task<PreconditionResult> CheckPermissions(IMessage context, Command executingCommand, object moduleInstance);
public abstract Task<PreconditionResult> CheckPermissions(IUserMessage context, Command executingCommand, object moduleInstance);
} }
} }

+ 1
- 1
src/Discord.Net.Commands/Attributes/Preconditions/RequireContextAttribute.cs View File

@@ -21,7 +21,7 @@ namespace Discord.Commands
Contexts = contexts; Contexts = contexts;
} }


public override Task<PreconditionResult> CheckPermissions(IMessage context, Command executingCommand, object moduleInstance)
public override Task<PreconditionResult> CheckPermissions(IUserMessage context, Command executingCommand, object moduleInstance)
{ {
bool isValid = false; bool isValid = false;




+ 1
- 1
src/Discord.Net.Commands/Attributes/Preconditions/RequirePermissionAttribute.cs View File

@@ -20,7 +20,7 @@ namespace Discord.Commands
GuildPermission = null; GuildPermission = null;
} }
public override Task<PreconditionResult> CheckPermissions(IMessage context, Command executingCommand, object moduleInstance)
public override Task<PreconditionResult> CheckPermissions(IUserMessage context, Command executingCommand, object moduleInstance)
{ {
var guildUser = context.Author as IGuildUser; var guildUser = context.Author as IGuildUser;




+ 11
- 11
src/Discord.Net.Commands/Command.cs View File

@@ -16,7 +16,7 @@ namespace Discord.Commands
private static readonly ConcurrentDictionary<Type, Func<IEnumerable<object>, object>> _arrayConverters = new ConcurrentDictionary<Type, Func<IEnumerable<object>, object>>(); private static readonly ConcurrentDictionary<Type, Func<IEnumerable<object>, object>> _arrayConverters = new ConcurrentDictionary<Type, Func<IEnumerable<object>, object>>();


private readonly object _instance; private readonly object _instance;
private readonly Func<IMessage, IReadOnlyList<object>, Task> _action;
private readonly Func<IUserMessage, IReadOnlyList<object>, Task> _action;


public MethodInfo Source { get; } public MethodInfo Source { get; }
public Module Module { get; } public Module Module { get; }
@@ -66,7 +66,7 @@ namespace Discord.Commands
_action = BuildAction(source); _action = BuildAction(source);
} }


public async Task<PreconditionResult> CheckPreconditions(IMessage context)
public async Task<PreconditionResult> CheckPreconditions(IUserMessage context)
{ {
foreach (PreconditionAttribute precondition in Module.Preconditions) foreach (PreconditionAttribute precondition in Module.Preconditions)
{ {
@@ -85,7 +85,7 @@ namespace Discord.Commands
return PreconditionResult.FromSuccess(); return PreconditionResult.FromSuccess();
} }


public async Task<ParseResult> Parse(IMessage msg, SearchResult searchResult, PreconditionResult? preconditionResult = null)
public async Task<ParseResult> Parse(IUserMessage context, SearchResult searchResult, PreconditionResult? preconditionResult = null)
{ {
if (!searchResult.IsSuccess) if (!searchResult.IsSuccess)
return ParseResult.FromError(searchResult); return ParseResult.FromError(searchResult);
@@ -104,9 +104,9 @@ namespace Discord.Commands
input = input.Substring(matchingAlias.Length); input = input.Substring(matchingAlias.Length);


return await CommandParser.ParseArgs(this, msg, input, 0).ConfigureAwait(false);
return await CommandParser.ParseArgs(this, context, input, 0).ConfigureAwait(false);
} }
public Task<ExecuteResult> Execute(IMessage msg, ParseResult parseResult)
public Task<ExecuteResult> Execute(IUserMessage context, ParseResult parseResult)
{ {
if (!parseResult.IsSuccess) if (!parseResult.IsSuccess)
return Task.FromResult(ExecuteResult.FromError(parseResult)); return Task.FromResult(ExecuteResult.FromError(parseResult));
@@ -127,13 +127,13 @@ namespace Discord.Commands
paramList[i] = parseResult.ParamValues[i].Values.First().Value; paramList[i] = parseResult.ParamValues[i].Values.First().Value;
} }


return Execute(msg, argList, paramList);
return Execute(context, argList, paramList);
} }
public async Task<ExecuteResult> Execute(IMessage msg, IEnumerable<object> argList, IEnumerable<object> paramList)
public async Task<ExecuteResult> Execute(IUserMessage context, IEnumerable<object> argList, IEnumerable<object> paramList)
{ {
try try
{ {
await _action.Invoke(msg, GenerateArgs(argList, paramList)).ConfigureAwait(false);//Note: This code may need context
await _action.Invoke(context, GenerateArgs(argList, paramList)).ConfigureAwait(false);//Note: This code may need context
return ExecuteResult.FromSuccess(); return ExecuteResult.FromSuccess();
} }
catch (Exception ex) catch (Exception ex)
@@ -150,8 +150,8 @@ namespace Discord.Commands
private IReadOnlyList<CommandParameter> BuildParameters(MethodInfo methodInfo) private IReadOnlyList<CommandParameter> BuildParameters(MethodInfo methodInfo)
{ {
var parameters = methodInfo.GetParameters(); var parameters = methodInfo.GetParameters();
if (parameters.Length == 0 || parameters[0].ParameterType != typeof(IMessage))
throw new InvalidOperationException("The first parameter of a command must be IMessage.");
if (parameters.Length == 0 || parameters[0].ParameterType != typeof(IUserMessage))
throw new InvalidOperationException($"The first parameter of a command must be {nameof(IUserMessage)}.");


var paramBuilder = ImmutableArray.CreateBuilder<CommandParameter>(parameters.Length - 1); var paramBuilder = ImmutableArray.CreateBuilder<CommandParameter>(parameters.Length - 1);
for (int i = 1; i < parameters.Length; i++) for (int i = 1; i < parameters.Length; i++)
@@ -190,7 +190,7 @@ namespace Discord.Commands
} }
return paramBuilder.ToImmutable(); return paramBuilder.ToImmutable();
} }
private Func<IMessage, IReadOnlyList<object>, Task> BuildAction(MethodInfo methodInfo)
private Func<IUserMessage, IReadOnlyList<object>, Task> BuildAction(MethodInfo methodInfo)
{ {
if (methodInfo.ReturnType != typeof(Task)) if (methodInfo.ReturnType != typeof(Task))
throw new InvalidOperationException("Commands must return a non-generic Task."); throw new InvalidOperationException("Commands must return a non-generic Task.");


+ 1
- 1
src/Discord.Net.Commands/CommandParameter.cs View File

@@ -32,7 +32,7 @@ namespace Discord.Commands
DefaultValue = defaultValue; DefaultValue = defaultValue;
} }


public async Task<TypeReaderResult> Parse(IMessage context, string input)
public async Task<TypeReaderResult> Parse(IUserMessage context, string input)
{ {
return await _reader.Read(context, input).ConfigureAwait(false); return await _reader.Read(context, input).ConfigureAwait(false);
} }


+ 1
- 1
src/Discord.Net.Commands/CommandParser.cs View File

@@ -13,7 +13,7 @@ namespace Discord.Commands
QuotedParameter QuotedParameter
} }
public static async Task<ParseResult> ParseArgs(Command command, IMessage context, string input, int startPos)
public static async Task<ParseResult> ParseArgs(Command command, IUserMessage context, string input, int startPos)
{ {
CommandParameter curParam = null; CommandParameter curParam = null;
StringBuilder argBuilder = new StringBuilder(input.Length); StringBuilder argBuilder = new StringBuilder(input.Length);


+ 7
- 6
src/Discord.Net.Commands/CommandService.cs View File

@@ -41,8 +41,9 @@ namespace Discord.Commands
[typeof(DateTime)] = new SimpleTypeReader<DateTime>(), [typeof(DateTime)] = new SimpleTypeReader<DateTime>(),
[typeof(DateTimeOffset)] = new SimpleTypeReader<DateTimeOffset>(), [typeof(DateTimeOffset)] = new SimpleTypeReader<DateTimeOffset>(),
[typeof(IMessage)] = new MessageTypeReader(),

[typeof(IMessage)] = new MessageTypeReader<IMessage>(),
[typeof(IUserMessage)] = new MessageTypeReader<IUserMessage>(),
//[typeof(ISystemMessage)] = new MessageTypeReader<ISystemMessage>(),
[typeof(IChannel)] = new ChannelTypeReader<IChannel>(), [typeof(IChannel)] = new ChannelTypeReader<IChannel>(),
[typeof(IDMChannel)] = new ChannelTypeReader<IDMChannel>(), [typeof(IDMChannel)] = new ChannelTypeReader<IDMChannel>(),
[typeof(IGroupChannel)] = new ChannelTypeReader<IGroupChannel>(), [typeof(IGroupChannel)] = new ChannelTypeReader<IGroupChannel>(),
@@ -175,8 +176,8 @@ namespace Discord.Commands
return false; return false;
} }


public SearchResult Search(IMessage message, int argPos) => Search(message, message.Content.Substring(argPos));
public SearchResult Search(IMessage message, string input)
public SearchResult Search(IUserMessage message, int argPos) => Search(message, message.Content.Substring(argPos));
public SearchResult Search(IUserMessage message, string input)
{ {
string lowerInput = input.ToLowerInvariant(); string lowerInput = input.ToLowerInvariant();
var matches = _map.GetCommands(input).ToImmutableArray(); var matches = _map.GetCommands(input).ToImmutableArray();
@@ -187,9 +188,9 @@ namespace Discord.Commands
return SearchResult.FromError(CommandError.UnknownCommand, "Unknown command."); return SearchResult.FromError(CommandError.UnknownCommand, "Unknown command.");
} }


public Task<IResult> Execute(IMessage message, int argPos, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
public Task<IResult> Execute(IUserMessage message, int argPos, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
=> Execute(message, message.Content.Substring(argPos), multiMatchHandling); => Execute(message, message.Content.Substring(argPos), multiMatchHandling);
public async Task<IResult> Execute(IMessage message, string input, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
public async Task<IResult> Execute(IUserMessage message, string input, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
{ {
var searchResult = Search(message, input); var searchResult = Search(message, input);
if (!searchResult.IsSuccess) if (!searchResult.IsSuccess)


+ 3
- 3
src/Discord.Net.Commands/Extensions/MessageExtensions.cs View File

@@ -2,7 +2,7 @@
{ {
public static class MessageExtensions public static class MessageExtensions
{ {
public static bool HasCharPrefix(this IMessage msg, char c, ref int argPos)
public static bool HasCharPrefix(this IUserMessage msg, char c, ref int argPos)
{ {
var text = msg.Content; var text = msg.Content;
if (text.Length > 0 && text[0] == c) if (text.Length > 0 && text[0] == c)
@@ -12,7 +12,7 @@
} }
return false; return false;
} }
public static bool HasStringPrefix(this IMessage msg, string str, ref int argPos)
public static bool HasStringPrefix(this IUserMessage msg, string str, ref int argPos)
{ {
var text = msg.Content; var text = msg.Content;
if (text.StartsWith(str)) if (text.StartsWith(str))
@@ -22,7 +22,7 @@
} }
return false; return false;
} }
public static bool HasMentionPrefix(this IMessage msg, IUser user, ref int argPos)
public static bool HasMentionPrefix(this IUserMessage msg, IUser user, ref int argPos)
{ {
var text = msg.Content; var text = msg.Content;
if (text.Length <= 3 || text[0] != '<' || text[1] != '@') return false; if (text.Length <= 3 || text[0] != '<' || text[1] != '@') return false;


+ 1
- 1
src/Discord.Net.Commands/Readers/ChannelTypeReader.cs View File

@@ -9,7 +9,7 @@ namespace Discord.Commands
internal class ChannelTypeReader<T> : TypeReader internal class ChannelTypeReader<T> : TypeReader
where T : class, IChannel where T : class, IChannel
{ {
public override async Task<TypeReaderResult> Read(IMessage context, string input)
public override async Task<TypeReaderResult> Read(IUserMessage context, string input)
{ {
var guild = (context.Channel as IGuildChannel)?.Guild; var guild = (context.Channel as IGuildChannel)?.Guild;




+ 1
- 1
src/Discord.Net.Commands/Readers/EnumTypeReader.cs View File

@@ -42,7 +42,7 @@ namespace Discord.Commands
_enumsByValue = byValueBuilder.ToImmutable(); _enumsByValue = byValueBuilder.ToImmutable();
} }


public override Task<TypeReaderResult> Read(IMessage context, string input)
public override Task<TypeReaderResult> Read(IUserMessage context, string input)
{ {
T baseValue; T baseValue;
object enumValue; object enumValue;


+ 4
- 3
src/Discord.Net.Commands/Readers/MessageTypeReader.cs View File

@@ -3,16 +3,17 @@ using System.Threading.Tasks;


namespace Discord.Commands namespace Discord.Commands
{ {
internal class MessageTypeReader : TypeReader
internal class MessageTypeReader<T> : TypeReader
where T : class, IMessage
{ {
public override Task<TypeReaderResult> Read(IMessage context, string input)
public override Task<TypeReaderResult> Read(IUserMessage context, string input)
{ {
ulong id; ulong id;


//By Id (1.0) //By Id (1.0)
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id)) if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id))
{ {
var msg = context.Channel.GetCachedMessage(id);
var msg = context.Channel.GetCachedMessage(id) as T;
if (msg != null) if (msg != null)
return Task.FromResult(TypeReaderResult.FromSuccess(msg)); return Task.FromResult(TypeReaderResult.FromSuccess(msg));
} }


+ 1
- 1
src/Discord.Net.Commands/Readers/RoleTypeReader.cs View File

@@ -9,7 +9,7 @@ namespace Discord.Commands
internal class RoleTypeReader<T> : TypeReader internal class RoleTypeReader<T> : TypeReader
where T : class, IRole where T : class, IRole
{ {
public override Task<TypeReaderResult> Read(IMessage context, string input)
public override Task<TypeReaderResult> Read(IUserMessage context, string input)
{ {
var guild = (context.Channel as IGuildChannel)?.Guild; var guild = (context.Channel as IGuildChannel)?.Guild;
ulong id; ulong id;


+ 1
- 1
src/Discord.Net.Commands/Readers/SimpleTypeReader.cs View File

@@ -11,7 +11,7 @@ namespace Discord.Commands
_tryParse = PrimitiveParsers.Get<T>(); _tryParse = PrimitiveParsers.Get<T>();
} }


public override Task<TypeReaderResult> Read(IMessage context, string input)
public override Task<TypeReaderResult> Read(IUserMessage context, string input)
{ {
T value; T value;
if (_tryParse(input, out value)) if (_tryParse(input, out value))


+ 1
- 1
src/Discord.Net.Commands/Readers/TypeReader.cs View File

@@ -4,6 +4,6 @@ namespace Discord.Commands
{ {
public abstract class TypeReader public abstract class TypeReader
{ {
public abstract Task<TypeReaderResult> Read(IMessage context, string input);
public abstract Task<TypeReaderResult> Read(IUserMessage context, string input);
} }
} }

+ 1
- 1
src/Discord.Net.Commands/Readers/UserTypeReader.cs View File

@@ -9,7 +9,7 @@ namespace Discord.Commands
internal class UserTypeReader<T> : TypeReader internal class UserTypeReader<T> : TypeReader
where T : class, IUser where T : class, IUser
{ {
public override async Task<TypeReaderResult> Read(IMessage context, string input)
public override async Task<TypeReaderResult> Read(IUserMessage context, string input)
{ {
var results = new Dictionary<ulong, TypeReaderValue>(); var results = new Dictionary<ulong, TypeReaderValue>();
var guild = (context.Channel as IGuildChannel)?.Guild; var guild = (context.Channel as IGuildChannel)?.Guild;


+ 0
- 2
src/Discord.Net/API/Rest/GetChannelMessagesParams.cs View File

@@ -1,6 +1,4 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using Discord.Rest;

namespace Discord.API.Rest namespace Discord.API.Rest
{ {
public class GetChannelMessagesParams public class GetChannelMessagesParams


+ 3
- 3
src/Discord.Net/Entities/Channels/IMessageChannel.cs View File

@@ -10,11 +10,11 @@ namespace Discord
IReadOnlyCollection<IMessage> CachedMessages { get; } IReadOnlyCollection<IMessage> CachedMessages { get; }


/// <summary> Sends a message to this message channel. </summary> /// <summary> Sends a message to this message channel. </summary>
Task<IMessage> SendMessageAsync(string text, bool isTTS = false);
Task<IUserMessage> SendMessageAsync(string text, bool isTTS = false);
/// <summary> Sends a file to this text channel, with an optional caption. </summary> /// <summary> Sends a file to this text channel, with an optional caption. </summary>
Task<IMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false);
Task<IUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false);
/// <summary> Sends a file to this text channel, with an optional caption. </summary> /// <summary> Sends a file to this text channel, with an optional caption. </summary>
Task<IMessage> SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false);
Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false);
/// <summary> Gets a message from this message channel with the given id, or null if not found. </summary> /// <summary> Gets a message from this message channel with the given id, or null if not found. </summary>
Task<IMessage> GetMessageAsync(ulong id); Task<IMessage> GetMessageAsync(ulong id);
/// <summary> Gets the message from this channel's cache with the given id, or null if not found. </summary> /// <summary> Gets the message from this channel's cache with the given id, or null if not found. </summary>


+ 5
- 28
src/Discord.Net/Entities/Messages/IMessage.cs View File

@@ -1,14 +1,10 @@
using System; using System;
using System.Threading.Tasks;
using Discord.API.Rest;
using System.Collections.Generic; using System.Collections.Generic;


namespace Discord namespace Discord
{ {
public interface IMessage : IDeletable, ISnowflakeEntity, IUpdateable
public interface IMessage : ISnowflakeEntity, IUpdateable
{ {
/// <summary> Gets the time of this message's last edit, if any. </summary>
DateTimeOffset? EditedTimestamp { get; }
/// <summary> Returns true if this message was sent as a text-to-speech message. </summary> /// <summary> Returns true if this message was sent as a text-to-speech message. </summary>
bool IsTTS { get; } bool IsTTS { get; }
/// <summary> Returns true if this message was added to its channel's pinned messages. </summary> /// <summary> Returns true if this message was added to its channel's pinned messages. </summary>
@@ -17,13 +13,14 @@ namespace Discord
string Content { get; } string Content { get; }
/// <summary> Gets the time this message was sent. </summary> /// <summary> Gets the time this message was sent. </summary>
DateTimeOffset Timestamp { get; } DateTimeOffset Timestamp { get; }
/// <summary> Gets the type of this message. </summary>
MessageType Type { get; }
/// <summary> Gets the time of this message's last edit, if any. </summary>
DateTimeOffset? EditedTimestamp { get; }
/// <summary> Gets the channel this message was sent to. </summary> /// <summary> Gets the channel this message was sent to. </summary>
IMessageChannel Channel { get; } IMessageChannel Channel { get; }
/// <summary> Gets the author of this message. </summary> /// <summary> Gets the author of this message. </summary>
IUser Author { get; } IUser Author { get; }

/// <summary> Returns a collection of all attachments included in this message. </summary> /// <summary> Returns a collection of all attachments included in this message. </summary>
IReadOnlyCollection<IAttachment> Attachments { get; } IReadOnlyCollection<IAttachment> Attachments { get; }
/// <summary> Returns a collection of all embeds included in this message. </summary> /// <summary> Returns a collection of all embeds included in this message. </summary>
@@ -34,25 +31,5 @@ namespace Discord
IReadOnlyCollection<IRole> MentionedRoles { get; } IReadOnlyCollection<IRole> MentionedRoles { get; }
/// <summary> Returns a collection of users mentioned in this message. </summary> /// <summary> Returns a collection of users mentioned in this message. </summary>
IReadOnlyCollection<IUser> MentionedUsers { get; } IReadOnlyCollection<IUser> MentionedUsers { get; }

/// <summary> Modifies this message. </summary>
Task ModifyAsync(Action<ModifyMessageParams> func);
/// <summary> Adds this message to its channel's pinned messages. </summary>
Task PinAsync();
/// <summary> Removes this message from its channel's pinned messages. </summary>
Task UnpinAsync();

/// <summary> Transforms this message's text into a human readable form, resolving things like mentions to that object's name. </summary>
string Resolve(int startIndex, int length,
UserMentionHandling userHandling = UserMentionHandling.Name,
ChannelMentionHandling channelHandling = ChannelMentionHandling.Name,
RoleMentionHandling roleHandling = RoleMentionHandling.Name,
EveryoneMentionHandling everyoneHandling = EveryoneMentionHandling.Ignore);
/// <summary> Transforms this message's text into a human readable form, resolving things like mentions to that object's name. </summary>
string Resolve(
UserMentionHandling userHandling = UserMentionHandling.Name,
ChannelMentionHandling channelHandling = ChannelMentionHandling.Name,
RoleMentionHandling roleHandling = RoleMentionHandling.Name,
EveryoneMentionHandling everyoneHandling = EveryoneMentionHandling.Ignore);
} }
} }

+ 8
- 0
src/Discord.Net/Entities/Messages/ISystemMessage.cs View File

@@ -0,0 +1,8 @@
namespace Discord
{
public interface ISystemMessage : IMessage
{
/// <summary> Gets the type of this system message. </summary>
MessageType Type { get; }
}
}

+ 29
- 0
src/Discord.Net/Entities/Messages/IUserMessage.cs View File

@@ -0,0 +1,29 @@
using Discord.API.Rest;
using System;
using System.Threading.Tasks;

namespace Discord
{
public interface IUserMessage : IMessage, IDeletable
{
/// <summary> Modifies this message. </summary>
Task ModifyAsync(Action<ModifyMessageParams> func);
/// <summary> Adds this message to its channel's pinned messages. </summary>
Task PinAsync();
/// <summary> Removes this message from its channel's pinned messages. </summary>
Task UnpinAsync();

/// <summary> Transforms this message's text into a human readable form, resolving mentions to that object's name. </summary>
string Resolve(int startIndex, int length,
UserMentionHandling userHandling = UserMentionHandling.Name,
ChannelMentionHandling channelHandling = ChannelMentionHandling.Name,
RoleMentionHandling roleHandling = RoleMentionHandling.Name,
EveryoneMentionHandling everyoneHandling = EveryoneMentionHandling.Ignore);
/// <summary> Transforms this message's text into a human readable form, resolving mentions to that object's name. </summary>
string Resolve(
UserMentionHandling userHandling = UserMentionHandling.Name,
ChannelMentionHandling channelHandling = ChannelMentionHandling.Name,
RoleMentionHandling roleHandling = RoleMentionHandling.Name,
EveryoneMentionHandling everyoneHandling = EveryoneMentionHandling.Ignore);
}
}

+ 25
- 12
src/Discord.Net/Rest/Entities/Channels/DMChannel.cs View File

@@ -7,6 +7,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Model = Discord.API.Channel; using Model = Discord.API.Channel;
using MessageModel = Discord.API.Message;


namespace Discord.Rest namespace Discord.Rest
{ {
@@ -62,46 +63,46 @@ namespace Discord.Rest
return ImmutableArray.Create(currentUser, Recipient); return ImmutableArray.Create(currentUser, Recipient);
} }


public async Task<IMessage> SendMessageAsync(string text, bool isTTS)
public async Task<IUserMessage> SendMessageAsync(string text, bool isTTS)
{ {
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(model.Author.Value), model);
return CreateOutgoingMessage(model);
} }
public async Task<IMessage> SendFileAsync(string filePath, string text, bool isTTS)
public async Task<IUserMessage> SendFileAsync(string filePath, string text, bool isTTS)
{ {
string filename = Path.GetFileName(filePath); string filename = Path.GetFileName(filePath);
using (var file = File.OpenRead(filePath)) using (var file = File.OpenRead(filePath))
{ {
var args = new UploadFileParams(file) { Filename = filename, Content = text, IsTTS = isTTS }; var args = new UploadFileParams(file) { Filename = filename, Content = text, IsTTS = isTTS };
var model = await Discord.ApiClient.UploadDMFileAsync(Id, args).ConfigureAwait(false); var model = await Discord.ApiClient.UploadDMFileAsync(Id, args).ConfigureAwait(false);
return new Message(this, new User(model.Author.Value), model);
return CreateOutgoingMessage(model);
} }
} }
public async Task<IMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS)
public async Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS)
{ {
var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS }; var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS };
var model = await Discord.ApiClient.UploadDMFileAsync(Id, args).ConfigureAwait(false); var model = await Discord.ApiClient.UploadDMFileAsync(Id, args).ConfigureAwait(false);
return new Message(this, new User(model.Author.Value), model);
return CreateOutgoingMessage(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(model.Author.Value), model);
return CreateIncomingMessage(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(x.Author.Value), x)).ToImmutableArray();
return models.Select(x => CreateIncomingMessage(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, RelativeMessageId = fromMessageId, RelativeDirection = dir }; var args = new GetChannelMessagesParams { Limit = limit, RelativeMessageId = fromMessageId, RelativeDirection = dir };
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(x.Author.Value), x)).ToImmutableArray();
return models.Select(x => CreateIncomingMessage(x)).ToImmutableArray();
} }
public async Task DeleteMessagesAsync(IEnumerable<IMessage> messages) public async Task DeleteMessagesAsync(IEnumerable<IMessage> messages)
{ {
@@ -110,14 +111,26 @@ namespace Discord.Rest
public async Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync() public async Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync()
{ {
var models = await Discord.ApiClient.GetPinsAsync(Id); var models = await Discord.ApiClient.GetPinsAsync(Id);
return models.Select(x => new Message(this, new User(x.Author.Value), x)).ToImmutableArray();
return models.Select(x => CreateIncomingMessage(x)).ToImmutableArray();
} }


public async Task TriggerTypingAsync() public async Task TriggerTypingAsync()
{ {
await Discord.ApiClient.TriggerTypingIndicatorAsync(Id).ConfigureAwait(false); await Discord.ApiClient.TriggerTypingIndicatorAsync(Id).ConfigureAwait(false);
}
}

private UserMessage CreateOutgoingMessage(MessageModel model)
{
return new UserMessage(this, new User(model.Author.Value), model);
}
private Message CreateIncomingMessage(MessageModel model)
{
if (model.Type == MessageType.Default)
return new UserMessage(this, new User(model.Author.Value), model);
else
return new SystemMessage(this, new User(model.Author.Value), model);
}

public override string ToString() => '@' + Recipient.ToString(); public override string ToString() => '@' + Recipient.ToString();
private string DebuggerDisplay => $"@{Recipient} ({Id}, DM)"; private string DebuggerDisplay => $"@{Recipient} ({Id}, DM)";


+ 23
- 10
src/Discord.Net/Rest/Entities/Channels/GroupChannel.cs View File

@@ -8,6 +8,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Model = Discord.API.Channel; using Model = Discord.API.Channel;
using MessageModel = Discord.API.Message;


namespace Discord.Rest namespace Discord.Rest
{ {
@@ -87,46 +88,46 @@ namespace Discord.Rest
return _users.Select(x => x.Value).Concat<IUser>(ImmutableArray.Create(currentUser)).ToReadOnlyCollection(_users); return _users.Select(x => x.Value).Concat<IUser>(ImmutableArray.Create(currentUser)).ToReadOnlyCollection(_users);
} }


public async Task<IMessage> SendMessageAsync(string text, bool isTTS)
public async Task<IUserMessage> SendMessageAsync(string text, bool isTTS)
{ {
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(model.Author.Value), model);
return CreateOutgoingMessage(model);
} }
public async Task<IMessage> SendFileAsync(string filePath, string text, bool isTTS)
public async Task<IUserMessage> SendFileAsync(string filePath, string text, bool isTTS)
{ {
string filename = Path.GetFileName(filePath); string filename = Path.GetFileName(filePath);
using (var file = File.OpenRead(filePath)) using (var file = File.OpenRead(filePath))
{ {
var args = new UploadFileParams(file) { Filename = filename, Content = text, IsTTS = isTTS }; var args = new UploadFileParams(file) { Filename = filename, Content = text, IsTTS = isTTS };
var model = await Discord.ApiClient.UploadDMFileAsync(Id, args).ConfigureAwait(false); var model = await Discord.ApiClient.UploadDMFileAsync(Id, args).ConfigureAwait(false);
return new Message(this, new User(model.Author.Value), model);
return CreateOutgoingMessage(model);
} }
} }
public async Task<IMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS)
public async Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS)
{ {
var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS }; var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS };
var model = await Discord.ApiClient.UploadDMFileAsync(Id, args).ConfigureAwait(false); var model = await Discord.ApiClient.UploadDMFileAsync(Id, args).ConfigureAwait(false);
return new Message(this, new User(model.Author.Value), model);
return CreateOutgoingMessage(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(model.Author.Value), model);
return CreateIncomingMessage(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(x.Author.Value), x)).ToImmutableArray();
return models.Select(x => CreateIncomingMessage(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, RelativeMessageId = fromMessageId, RelativeDirection = dir }; var args = new GetChannelMessagesParams { Limit = limit, RelativeMessageId = fromMessageId, RelativeDirection = dir };
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(x.Author.Value), x)).ToImmutableArray();
return models.Select(x => CreateIncomingMessage(x)).ToImmutableArray();
} }
public async Task DeleteMessagesAsync(IEnumerable<IMessage> messages) public async Task DeleteMessagesAsync(IEnumerable<IMessage> messages)
{ {
@@ -135,7 +136,7 @@ namespace Discord.Rest
public async Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync() public async Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync()
{ {
var models = await Discord.ApiClient.GetPinsAsync(Id); var models = await Discord.ApiClient.GetPinsAsync(Id);
return models.Select(x => new Message(this, new User(x.Author.Value), x)).ToImmutableArray();
return models.Select(x => CreateIncomingMessage(x)).ToImmutableArray();
} }


public async Task TriggerTypingAsync() public async Task TriggerTypingAsync()
@@ -143,6 +144,18 @@ namespace Discord.Rest
await Discord.ApiClient.TriggerTypingIndicatorAsync(Id).ConfigureAwait(false); await Discord.ApiClient.TriggerTypingIndicatorAsync(Id).ConfigureAwait(false);
} }


private UserMessage CreateOutgoingMessage(MessageModel model)
{
return new UserMessage(this, new User(model.Author.Value), model);
}
private Message CreateIncomingMessage(MessageModel model)
{
if (model.Type == MessageType.Default)
return new UserMessage(this, new User(model.Author.Value), model);
else
return new SystemMessage(this, new User(model.Author.Value), model);
}

public override string ToString() => Name; public override string ToString() => Name;
private string DebuggerDisplay => $"@{Name} ({Id}, Group)"; private string DebuggerDisplay => $"@{Name} ({Id}, Group)";




+ 23
- 10
src/Discord.Net/Rest/Entities/Channels/TextChannel.cs View File

@@ -7,6 +7,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Model = Discord.API.Channel; using Model = Discord.API.Channel;
using MessageModel = Discord.API.Message;


namespace Discord.Rest namespace Discord.Rest
{ {
@@ -57,46 +58,46 @@ namespace Discord.Rest
return users.Where(x => Permissions.GetValue(Permissions.ResolveChannel(x, this, x.GuildPermissions.RawValue), ChannelPermission.ReadMessages)).ToImmutableArray(); return users.Where(x => Permissions.GetValue(Permissions.ResolveChannel(x, this, x.GuildPermissions.RawValue), ChannelPermission.ReadMessages)).ToImmutableArray();
} }


public async Task<IMessage> SendMessageAsync(string text, bool isTTS)
public async Task<IUserMessage> SendMessageAsync(string text, bool isTTS)
{ {
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(model.Author.Value), model);
return CreateOutgoingMessage(model);
} }
public async Task<IMessage> SendFileAsync(string filePath, string text, bool isTTS)
public async Task<IUserMessage> SendFileAsync(string filePath, string text, bool isTTS)
{ {
string filename = Path.GetFileName(filePath); string filename = Path.GetFileName(filePath);
using (var file = File.OpenRead(filePath)) using (var file = File.OpenRead(filePath))
{ {
var args = new UploadFileParams(file) { Filename = filename, Content = text, IsTTS = isTTS }; var args = new UploadFileParams(file) { Filename = filename, Content = text, IsTTS = isTTS };
var model = await Discord.ApiClient.UploadFileAsync(Guild.Id, Id, args).ConfigureAwait(false); var model = await Discord.ApiClient.UploadFileAsync(Guild.Id, Id, args).ConfigureAwait(false);
return new Message(this, new User(model.Author.Value), model);
return CreateOutgoingMessage(model);
} }
} }
public async Task<IMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS)
public async Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS)
{ {
var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS }; var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS };
var model = await Discord.ApiClient.UploadFileAsync(Guild.Id, Id, args).ConfigureAwait(false); var model = await Discord.ApiClient.UploadFileAsync(Guild.Id, Id, args).ConfigureAwait(false);
return new Message(this, new User(model.Author.Value), model);
return CreateOutgoingMessage(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(model.Author.Value), model);
return CreateIncomingMessage(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(x.Author.Value), x)).ToImmutableArray();
return models.Select(x => CreateIncomingMessage(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, RelativeMessageId = fromMessageId, RelativeDirection = dir }; var args = new GetChannelMessagesParams { Limit = limit, RelativeMessageId = fromMessageId, RelativeDirection = dir };
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(x.Author.Value), x)).ToImmutableArray();
return models.Select(x => CreateIncomingMessage(x)).ToImmutableArray();
} }
public async Task DeleteMessagesAsync(IEnumerable<IMessage> messages) public async Task DeleteMessagesAsync(IEnumerable<IMessage> messages)
{ {
@@ -105,7 +106,7 @@ namespace Discord.Rest
public async Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync() public async Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync()
{ {
var models = await Discord.ApiClient.GetPinsAsync(Id); var models = await Discord.ApiClient.GetPinsAsync(Id);
return models.Select(x => new Message(this, new User(x.Author.Value), x)).ToImmutableArray();
return models.Select(x => CreateIncomingMessage(x)).ToImmutableArray();
} }


public async Task TriggerTypingAsync() public async Task TriggerTypingAsync()
@@ -113,6 +114,18 @@ namespace Discord.Rest
await Discord.ApiClient.TriggerTypingIndicatorAsync(Id).ConfigureAwait(false); await Discord.ApiClient.TriggerTypingIndicatorAsync(Id).ConfigureAwait(false);
} }


private UserMessage CreateOutgoingMessage(MessageModel model)
{
return new UserMessage(this, new User(model.Author.Value), model);
}
private Message CreateIncomingMessage(MessageModel model)
{
if (model.Type == MessageType.Default)
return new UserMessage(this, new User(model.Author.Value), model);
else
return new SystemMessage(this, new User(model.Author.Value), model);
}

private string DebuggerDisplay => $"{Name} ({Id}, Text)"; private string DebuggerDisplay => $"{Name} ({Id}, Text)";


IMessage IMessageChannel.GetCachedMessage(ulong id) => null; IMessage IMessageChannel.GetCachedMessage(ulong id) => null;


+ 15
- 98
src/Discord.Net/Rest/Entities/Messages/Message.cs View File

@@ -9,28 +9,27 @@ using Model = Discord.API.Message;
namespace Discord.Rest namespace Discord.Rest
{ {
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
internal class Message : SnowflakeEntity, IMessage
internal abstract class Message : SnowflakeEntity, IMessage
{ {
private bool _isMentioningEveryone;
private long _timestampTicks; private long _timestampTicks;
private long? _editedTimestampTicks;
public MessageType Type { get; }
public IMessageChannel Channel { get; } public IMessageChannel Channel { get; }
public IUser Author { get; } public IUser Author { get; }


public bool IsTTS { get; private set; }
public string Content { get; private set; } public string Content { get; private set; }
public bool IsPinned { get; private set; }

public IReadOnlyCollection<IAttachment> Attachments { get; private set; }
public IReadOnlyCollection<IEmbed> Embeds { get; private set; }
public IReadOnlyCollection<ulong> MentionedChannelIds { get; private set; }
public IReadOnlyCollection<IRole> MentionedRoles { get; private set; }
public IReadOnlyCollection<IUser> MentionedUsers { get; private set; }


public override DiscordRestClient Discord => (Channel as Entity<ulong>).Discord; public override DiscordRestClient Discord => (Channel as Entity<ulong>).Discord;
public DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks);

public virtual bool IsTTS => false;
public virtual bool IsPinned => false;
public virtual DateTimeOffset? EditedTimestamp => null;

public virtual IReadOnlyCollection<IAttachment> Attachments => ImmutableArray.Create<IAttachment>();
public virtual IReadOnlyCollection<IEmbed> Embeds => ImmutableArray.Create<IEmbed>();
public virtual IReadOnlyCollection<ulong> MentionedChannelIds => ImmutableArray.Create<ulong>();
public virtual IReadOnlyCollection<IRole> MentionedRoles => ImmutableArray.Create<IRole>();
public virtual IReadOnlyCollection<IUser> MentionedUsers => ImmutableArray.Create<IUser>();

public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks); public DateTimeOffset Timestamp => DateTimeUtils.FromTicks(_timestampTicks);


public Message(IMessageChannel channel, IUser author, Model model) public Message(IMessageChannel channel, IUser author, Model model)
@@ -38,86 +37,21 @@ namespace Discord.Rest
{ {
Channel = channel; Channel = channel;
Author = author; Author = author;
Type = model.Type;
MentionedUsers = ImmutableArray.Create<IUser>();
MentionedChannelIds = ImmutableArray.Create<ulong>();
MentionedRoles = ImmutableArray.Create<IRole>();


Update(model, UpdateSource.Creation); Update(model, UpdateSource.Creation);
} }
public void Update(Model model, UpdateSource source)
public virtual void Update(Model model, UpdateSource source)
{ {
if (source == UpdateSource.Rest && IsAttached) return; if (source == UpdateSource.Rest && IsAttached) return;


var guildChannel = Channel as GuildChannel; var guildChannel = Channel as GuildChannel;
var guild = guildChannel?.Guild; var guild = guildChannel?.Guild;

if (model.IsTextToSpeech.IsSpecified)
IsTTS = model.IsTextToSpeech.Value;
if (model.Pinned.IsSpecified)
IsPinned = model.Pinned.Value;
if (model.Timestamp.IsSpecified) if (model.Timestamp.IsSpecified)
_timestampTicks = model.Timestamp.Value.UtcTicks; _timestampTicks = model.Timestamp.Value.UtcTicks;
if (model.EditedTimestamp.IsSpecified)
_editedTimestampTicks = model.EditedTimestamp.Value?.UtcTicks;
if (model.MentionEveryone.IsSpecified)
_isMentioningEveryone = model.MentionEveryone.Value;

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(value[i]);
MentionedUsers = ImmutableArray.Create(mentions);
}
else
MentionedUsers = ImmutableArray.Create<IUser>();
}


if (model.Content.IsSpecified) if (model.Content.IsSpecified)
{
var text = model.Content.Value;
if (guildChannel != null)
{
MentionedUsers = MentionUtils.GetUserMentions(text, Channel, MentionedUsers);
MentionedChannelIds = MentionUtils.GetChannelMentions(text, guildChannel.Guild);
MentionedRoles = MentionUtils.GetRoleMentions(text, guildChannel.Guild);
}
Content = text;
}
Content = model.Content.Value;
} }


public async Task UpdateAsync() public async Task UpdateAsync()
@@ -159,23 +93,6 @@ namespace Discord.Rest
{ {
await Discord.ApiClient.RemovePinAsync(Channel.Id, Id).ConfigureAwait(false); await Discord.ApiClient.RemovePinAsync(Channel.Id, Id).ConfigureAwait(false);
} }
public string Resolve(int startIndex, int length, UserMentionHandling userHandling, ChannelMentionHandling channelHandling,
RoleMentionHandling roleHandling, EveryoneMentionHandling everyoneHandling)
=> Resolve(Content.Substring(startIndex, length), userHandling, channelHandling, roleHandling, everyoneHandling);
public string Resolve(UserMentionHandling userHandling, ChannelMentionHandling channelHandling,
RoleMentionHandling roleHandling, EveryoneMentionHandling everyoneHandling)
=> Resolve(Content, userHandling, channelHandling, roleHandling, everyoneHandling);
private string Resolve(string text, UserMentionHandling userHandling, ChannelMentionHandling channelHandling,
RoleMentionHandling roleHandling, EveryoneMentionHandling everyoneHandling)
{
text = MentionUtils.ResolveUserMentions(text, Channel, MentionedUsers, userHandling);
text = MentionUtils.ResolveChannelMentions(text, (Channel as IGuildChannel)?.Guild, channelHandling);
text = MentionUtils.ResolveRoleMentions(text, MentionedRoles, roleHandling);
text = MentionUtils.ResolveEveryoneMentions(text, everyoneHandling);
return text;
}


public override string ToString() => Content; public override string ToString() => Content;
private string DebuggerDisplay => $"{Author}: {Content}{(Attachments.Count > 0 ? $" [{Attachments.Count} Attachments]" : "")}"; private string DebuggerDisplay => $"{Author}: {Content}{(Attachments.Count > 0 ? $" [{Attachments.Count} Attachments]" : "")}";


+ 22
- 0
src/Discord.Net/Rest/Entities/Messages/SystemMessage.cs View File

@@ -0,0 +1,22 @@
using System.Diagnostics;
using Model = Discord.API.Message;

namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
internal class SystemMessage : Message, ISystemMessage
{
public MessageType Type { get; }

public override DiscordRestClient Discord => (Channel as Entity<ulong>).Discord;

public SystemMessage(IMessageChannel channel, IUser author, Model model)
: base(channel, author, model)
{
Type = model.Type;
}
public override string ToString() => Content;
private string DebuggerDisplay => $"[{Type}] {Author}{(!string.IsNullOrEmpty(Content) ? $": ({Content})" : "")}";
}
}

+ 175
- 0
src/Discord.Net/Rest/Entities/Messages/UserMessage.cs View File

@@ -0,0 +1,175 @@
using Discord.API.Rest;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading.Tasks;
using Model = Discord.API.Message;

namespace Discord.Rest
{
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
internal class UserMessage : Message, IUserMessage
{
private bool _isMentioningEveryone, _isTTS, _isPinned;
private long? _editedTimestampTicks;
private IReadOnlyCollection<IAttachment> _attachments;
private IReadOnlyCollection<IEmbed> _embeds;
private IReadOnlyCollection<ulong> _mentionedChannelIds;
private IReadOnlyCollection<IRole> _mentionedRoles;
private IReadOnlyCollection<IUser> _mentionedUsers;

public override DiscordRestClient Discord => (Channel as Entity<ulong>).Discord;
public override bool IsTTS => _isTTS;
public override bool IsPinned => _isPinned;
public override DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks);

public override IReadOnlyCollection<IAttachment> Attachments => _attachments;
public override IReadOnlyCollection<IEmbed> Embeds => _embeds;
public override IReadOnlyCollection<ulong> MentionedChannelIds => _mentionedChannelIds;
public override IReadOnlyCollection<IRole> MentionedRoles => _mentionedRoles;
public override IReadOnlyCollection<IUser> MentionedUsers => _mentionedUsers;

public UserMessage(IMessageChannel channel, IUser author, Model model)
: base(channel, author, model)
{
_mentionedChannelIds = ImmutableArray.Create<ulong>();
_mentionedRoles = ImmutableArray.Create<IRole>();
_mentionedUsers = ImmutableArray.Create<IUser>();

Update(model, UpdateSource.Creation);
}
public override void Update(Model model, UpdateSource source)
{
if (source == UpdateSource.Rest && IsAttached) return;

var guildChannel = Channel as GuildChannel;
var guild = guildChannel?.Guild;

if (model.IsTextToSpeech.IsSpecified)
_isTTS = model.IsTextToSpeech.Value;
if (model.Pinned.IsSpecified)
_isPinned = model.Pinned.Value;
if (model.EditedTimestamp.IsSpecified)
_editedTimestampTicks = model.EditedTimestamp.Value?.UtcTicks;
if (model.MentionEveryone.IsSpecified)
_isMentioningEveryone = model.MentionEveryone.Value;

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

ImmutableArray<IUser> mentions = ImmutableArray.Create<IUser>();
if (model.Mentions.IsSpecified)
{
var value = model.Mentions.Value;
if (value.Length > 0)
{
var newMentions = new IUser[value.Length];
for (int i = 0; i < value.Length; i++)
newMentions[i] = new User(value[i]);
mentions = ImmutableArray.Create(newMentions);
}
}

if (model.Content.IsSpecified)
{
var text = model.Content.Value;
if (guildChannel != null)
{
_mentionedUsers = MentionUtils.GetUserMentions(text, Channel, mentions);
_mentionedChannelIds = MentionUtils.GetChannelMentions(text, guildChannel.Guild);
_mentionedRoles = MentionUtils.GetRoleMentions(text, guildChannel.Guild);
}
model.Content = text;
}

base.Update(model, source);
}

public async Task UpdateAsync()
{
if (IsAttached) throw new NotSupportedException();

var model = await Discord.ApiClient.GetChannelMessageAsync(Channel.Id, Id).ConfigureAwait(false);
Update(model, UpdateSource.Rest);
}
public async Task ModifyAsync(Action<ModifyMessageParams> func)
{
if (func == null) throw new NullReferenceException(nameof(func));

var args = new ModifyMessageParams();
func(args);
var guildChannel = Channel as GuildChannel;

Model model;
if (guildChannel != null)
model = await Discord.ApiClient.ModifyMessageAsync(guildChannel.Guild.Id, Channel.Id, Id, args).ConfigureAwait(false);
else
model = await Discord.ApiClient.ModifyDMMessageAsync(Channel.Id, Id, args).ConfigureAwait(false);
Update(model, UpdateSource.Rest);
}
public async Task DeleteAsync()
{
var guildChannel = Channel as GuildChannel;
if (guildChannel != null)
await Discord.ApiClient.DeleteMessageAsync(guildChannel.Id, Channel.Id, Id).ConfigureAwait(false);
else
await Discord.ApiClient.DeleteDMMessageAsync(Channel.Id, Id).ConfigureAwait(false);
}
public async Task PinAsync()
{
await Discord.ApiClient.AddPinAsync(Channel.Id, Id).ConfigureAwait(false);
}
public async Task UnpinAsync()
{
await Discord.ApiClient.RemovePinAsync(Channel.Id, Id).ConfigureAwait(false);
}
public string Resolve(int startIndex, int length, UserMentionHandling userHandling, ChannelMentionHandling channelHandling,
RoleMentionHandling roleHandling, EveryoneMentionHandling everyoneHandling)
=> Resolve(Content.Substring(startIndex, length), userHandling, channelHandling, roleHandling, everyoneHandling);
public string Resolve(UserMentionHandling userHandling, ChannelMentionHandling channelHandling,
RoleMentionHandling roleHandling, EveryoneMentionHandling everyoneHandling)
=> Resolve(Content, userHandling, channelHandling, roleHandling, everyoneHandling);
private string Resolve(string text, UserMentionHandling userHandling, ChannelMentionHandling channelHandling,
RoleMentionHandling roleHandling, EveryoneMentionHandling everyoneHandling)
{
text = MentionUtils.ResolveUserMentions(text, Channel, MentionedUsers, userHandling);
text = MentionUtils.ResolveChannelMentions(text, (Channel as IGuildChannel)?.Guild, channelHandling);
text = MentionUtils.ResolveRoleMentions(text, MentionedRoles, roleHandling);
text = MentionUtils.ResolveEveryoneMentions(text, everyoneHandling);
return text;
}

public override string ToString() => Content;
private string DebuggerDisplay => $"{Author}: {Content}{(Attachments.Count > 0 ? $" [{Attachments.Count} Attachments]" : "")}";
}
}

+ 2
- 2
src/Discord.Net/WebSocket/DiscordSocketClient.cs View File

@@ -1247,7 +1247,7 @@ namespace Discord.WebSocket
} }


IMessage before = null, after = null; IMessage before = null, after = null;
SocketMessage cachedMsg = channel.GetMessage(data.Id);
ISocketMessage cachedMsg = channel.GetMessage(data.Id);
if (cachedMsg != null) if (cachedMsg != null)
{ {
before = cachedMsg.Clone(); before = cachedMsg.Clone();
@@ -1259,7 +1259,7 @@ namespace Discord.WebSocket
//Edited message isnt in cache, create a detached one //Edited message isnt in cache, create a detached one
var author = channel.GetUser(data.Author.Value.Id, true); var author = channel.GetUser(data.Author.Value.Id, true);
if (author != null) if (author != null)
after = new Message(channel, author, data);
after = channel.CreateMessage(author, data);
} }
if (after != null) if (after != null)
await _messageUpdatedEvent.InvokeAsync(Optional.Create(before), after).ConfigureAwait(false); await _messageUpdatedEvent.InvokeAsync(Optional.Create(before), after).ConfigureAwait(false);


+ 4
- 3
src/Discord.Net/WebSocket/Entities/Channels/ISocketMessageChannel.cs View File

@@ -7,9 +7,10 @@ namespace Discord.WebSocket
{ {
IReadOnlyCollection<ISocketUser> Users { get; } IReadOnlyCollection<ISocketUser> Users { get; }


SocketMessage AddMessage(ISocketUser author, MessageModel model);
SocketMessage GetMessage(ulong id);
SocketMessage RemoveMessage(ulong id);
ISocketMessage CreateMessage(ISocketUser author, MessageModel model);
ISocketMessage AddMessage(ISocketUser author, MessageModel model);
ISocketMessage GetMessage(ulong id);
ISocketMessage RemoveMessage(ulong id);


ISocketUser GetUser(ulong id, bool skipCheck = false); ISocketUser GetUser(ulong id, bool skipCheck = false);
} }


+ 13
- 13
src/Discord.Net/WebSocket/Entities/Channels/MessageCache.cs View File

@@ -9,51 +9,51 @@ namespace Discord.WebSocket
{ {
internal class MessageCache : MessageManager internal class MessageCache : MessageManager
{ {
private readonly ConcurrentDictionary<ulong, SocketMessage> _messages;
private readonly ConcurrentDictionary<ulong, ISocketMessage> _messages;
private readonly ConcurrentQueue<ulong> _orderedMessages; private readonly ConcurrentQueue<ulong> _orderedMessages;
private readonly int _size; private readonly int _size;


public override IReadOnlyCollection<SocketMessage> Messages => _messages.ToReadOnlyCollection();
public override IReadOnlyCollection<ISocketMessage> Messages => _messages.ToReadOnlyCollection();


public MessageCache(DiscordSocketClient discord, ISocketMessageChannel channel) public MessageCache(DiscordSocketClient discord, ISocketMessageChannel channel)
: base(discord, channel) : base(discord, channel)
{ {
_size = discord.MessageCacheSize; _size = discord.MessageCacheSize;
_messages = new ConcurrentDictionary<ulong, SocketMessage>(1, (int)(_size * 1.05));
_messages = new ConcurrentDictionary<ulong, ISocketMessage>(1, (int)(_size * 1.05));
_orderedMessages = new ConcurrentQueue<ulong>(); _orderedMessages = new ConcurrentQueue<ulong>();
} }


public override void Add(SocketMessage message)
public override void Add(ISocketMessage message)
{ {
if (_messages.TryAdd(message.Id, message)) if (_messages.TryAdd(message.Id, message))
{ {
_orderedMessages.Enqueue(message.Id); _orderedMessages.Enqueue(message.Id);


ulong msgId; ulong msgId;
SocketMessage msg;
ISocketMessage msg;
while (_orderedMessages.Count > _size && _orderedMessages.TryDequeue(out msgId)) while (_orderedMessages.Count > _size && _orderedMessages.TryDequeue(out msgId))
_messages.TryRemove(msgId, out msg); _messages.TryRemove(msgId, out msg);
} }
} }


public override SocketMessage Remove(ulong id)
public override ISocketMessage Remove(ulong id)
{ {
SocketMessage msg;
ISocketMessage msg;
_messages.TryRemove(id, out msg); _messages.TryRemove(id, out msg);
return msg; return msg;
} }


public override SocketMessage Get(ulong id)
public override ISocketMessage Get(ulong id)
{ {
SocketMessage result;
ISocketMessage result;
if (_messages.TryGetValue(id, out result)) if (_messages.TryGetValue(id, out result))
return result; return result;
return null; return null;
} }
public override IImmutableList<SocketMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch)
public override IImmutableList<ISocketMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch)
{ {
if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit)); if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit));
if (limit == 0) return ImmutableArray<SocketMessage>.Empty;
if (limit == 0) return ImmutableArray<ISocketMessage>.Empty;


IEnumerable<ulong> cachedMessageIds; IEnumerable<ulong> cachedMessageIds;
if (fromMessageId == null) if (fromMessageId == null)
@@ -67,7 +67,7 @@ namespace Discord.WebSocket
.Take(limit) .Take(limit)
.Select(x => .Select(x =>
{ {
SocketMessage msg;
ISocketMessage msg;
if (_messages.TryGetValue(x, out msg)) if (_messages.TryGetValue(x, out msg))
return msg; return msg;
return null; return null;
@@ -76,7 +76,7 @@ namespace Discord.WebSocket
.ToImmutableArray(); .ToImmutableArray();
} }


public override async Task<SocketMessage> DownloadAsync(ulong id)
public override async Task<ISocketMessage> DownloadAsync(ulong id)
{ {
var msg = Get(id); var msg = Get(id);
if (msg != null) if (msg != null)


+ 21
- 12
src/Discord.Net/WebSocket/Entities/Channels/MessageManager.cs View File

@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Model = Discord.API.Message;


namespace Discord.WebSocket namespace Discord.WebSocket
{ {
@@ -13,8 +14,8 @@ namespace Discord.WebSocket
private readonly DiscordSocketClient _discord; private readonly DiscordSocketClient _discord;
private readonly ISocketMessageChannel _channel; private readonly ISocketMessageChannel _channel;


public virtual IReadOnlyCollection<SocketMessage> Messages
=> ImmutableArray.Create<SocketMessage>();
public virtual IReadOnlyCollection<ISocketMessage> Messages
=> ImmutableArray.Create<ISocketMessage>();


public MessageManager(DiscordSocketClient discord, ISocketMessageChannel channel) public MessageManager(DiscordSocketClient discord, ISocketMessageChannel channel)
{ {
@@ -22,25 +23,25 @@ namespace Discord.WebSocket
_channel = channel; _channel = channel;
} }


public virtual void Add(SocketMessage message) { }
public virtual SocketMessage Remove(ulong id) => null;
public virtual SocketMessage Get(ulong id) => null;
public virtual void Add(ISocketMessage message) { }
public virtual ISocketMessage Remove(ulong id) => null;
public virtual ISocketMessage Get(ulong id) => null;


public virtual IImmutableList<SocketMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch)
=> ImmutableArray.Create<SocketMessage>();
public virtual IImmutableList<ISocketMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch)
=> ImmutableArray.Create<ISocketMessage>();


public virtual async Task<SocketMessage> DownloadAsync(ulong id)
public virtual async Task<ISocketMessage> DownloadAsync(ulong id)
{ {
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 SocketMessage(_channel, new User(model.Author.Value), model);
return Create(new User(model.Author.Value), model);
return null; return null;
} }
public async Task<IReadOnlyCollection<SocketMessage>> DownloadAsync(ulong? fromId, Direction dir, int limit)
public async Task<IReadOnlyCollection<ISocketMessage>> DownloadAsync(ulong? fromId, Direction dir, int limit)
{ {
//TODO: Test heavily, especially the ordering of messages //TODO: Test heavily, especially the ordering of messages
if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit)); if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit));
if (limit == 0) return ImmutableArray<SocketMessage>.Empty;
if (limit == 0) return ImmutableArray<ISocketMessage>.Empty;


var cachedMessages = GetMany(fromId, dir, limit); var cachedMessages = GetMany(fromId, dir, limit);
if (cachedMessages.Count == limit) if (cachedMessages.Count == limit)
@@ -75,9 +76,17 @@ namespace Discord.WebSocket
else else
user = newUser; user = newUser;
} }
return new SocketMessage(_channel, user, x);
return Create(user, x);
})).ToImmutableArray(); })).ToImmutableArray();
} }
} }

public ISocketMessage Create(IUser author, Model model)
{
if (model.Type == MessageType.Default)
return new SocketUserMessage(_channel, author, model);
else
return new SocketSystemMessage(_channel, author, model);
}
} }
} }

+ 8
- 4
src/Discord.Net/WebSocket/Entities/Channels/SocketDMChannel.cs View File

@@ -52,17 +52,21 @@ namespace Discord.WebSocket
{ {
return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false); return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false);
} }
public SocketMessage AddMessage(ISocketUser author, MessageModel model)
public ISocketMessage CreateMessage(ISocketUser author, MessageModel model)
{ {
var msg = new SocketMessage(this, author, model);
return _messages.Create(author, model);
}
public ISocketMessage AddMessage(ISocketUser author, MessageModel model)
{
var msg = _messages.Create(author, model);
_messages.Add(msg); _messages.Add(msg);
return msg; return msg;
} }
public SocketMessage GetMessage(ulong id)
public ISocketMessage GetMessage(ulong id)
{ {
return _messages.Get(id); return _messages.Get(id);
} }
public SocketMessage RemoveMessage(ulong id)
public ISocketMessage RemoveMessage(ulong id)
{ {
return _messages.Remove(id); return _messages.Remove(id);
} }


+ 8
- 4
src/Discord.Net/WebSocket/Entities/Channels/SocketGroupChannel.cs View File

@@ -116,17 +116,21 @@ namespace Discord.WebSocket
{ {
return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false); return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false);
} }
public SocketMessage AddMessage(ISocketUser author, MessageModel model)
public ISocketMessage CreateMessage(ISocketUser author, MessageModel model)
{ {
var msg = new SocketMessage(this, author, model);
return _messages.Create(author, model);
}
public ISocketMessage AddMessage(ISocketUser author, MessageModel model)
{
var msg = _messages.Create(author, model);
_messages.Add(msg); _messages.Add(msg);
return msg; return msg;
} }
public SocketMessage GetMessage(ulong id)
public ISocketMessage GetMessage(ulong id)
{ {
return _messages.Get(id); return _messages.Get(id);
} }
public SocketMessage RemoveMessage(ulong id)
public ISocketMessage RemoveMessage(ulong id)
{ {
return _messages.Remove(id); return _messages.Remove(id);
} }


+ 8
- 4
src/Discord.Net/WebSocket/Entities/Channels/SocketTextChannel.cs View File

@@ -58,17 +58,21 @@ namespace Discord.WebSocket
return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false); return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false);
} }


public SocketMessage AddMessage(ISocketUser author, MessageModel model)
public ISocketMessage CreateMessage(ISocketUser author, MessageModel model)
{ {
var msg = new SocketMessage(this, author, model);
return _messages.Create(author, model);
}
public ISocketMessage AddMessage(ISocketUser author, MessageModel model)
{
var msg = _messages.Create(author, model);
_messages.Add(msg); _messages.Add(msg);
return msg; return msg;
} }
public SocketMessage GetMessage(ulong id)
public ISocketMessage GetMessage(ulong id)
{ {
return _messages.Get(id); return _messages.Get(id);
} }
public SocketMessage RemoveMessage(ulong id)
public ISocketMessage RemoveMessage(ulong id)
{ {
return _messages.Remove(id); return _messages.Remove(id);
} }


+ 13
- 0
src/Discord.Net/WebSocket/Entities/Messages/ISocketMessage.cs View File

@@ -0,0 +1,13 @@
using Model = Discord.API.Message;

namespace Discord.WebSocket
{
internal interface ISocketMessage : IMessage
{
DiscordSocketClient Discord { get; }
new ISocketMessageChannel Channel { get; }

void Update(Model model, UpdateSource source);
ISocketMessage Clone();
}
}

+ 20
- 0
src/Discord.Net/WebSocket/Entities/Messages/SocketSystemMessage.cs View File

@@ -0,0 +1,20 @@
using Discord.Rest;
using Model = Discord.API.Message;

namespace Discord.WebSocket
{
internal class SocketSystemMessage : SystemMessage, ISocketMessage
{
internal override bool IsAttached => true;

public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
public new ISocketMessageChannel Channel => base.Channel as ISocketMessageChannel;

public SocketSystemMessage(ISocketMessageChannel channel, IUser author, Model model)
: base(channel, author, model)
{
}

public ISocketMessage Clone() => MemberwiseClone() as ISocketMessage;
}
}

src/Discord.Net/WebSocket/Entities/Messages/SocketMessage.cs → src/Discord.Net/WebSocket/Entities/Messages/SocketUserMessage.cs View File

@@ -3,18 +3,18 @@ using Model = Discord.API.Message;


namespace Discord.WebSocket namespace Discord.WebSocket
{ {
internal class SocketMessage : Message
internal class SocketUserMessage : UserMessage, ISocketMessage
{ {
internal override bool IsAttached => true; internal override bool IsAttached => true;


public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
public new ISocketMessageChannel Channel => base.Channel as ISocketMessageChannel; public new ISocketMessageChannel Channel => base.Channel as ISocketMessageChannel;


public SocketMessage(ISocketMessageChannel channel, IUser author, Model model)
public SocketUserMessage(ISocketMessageChannel channel, IUser author, Model model)
: base(channel, author, model) : base(channel, author, model)
{ {
} }


public SocketMessage Clone() => MemberwiseClone() as SocketMessage;
public ISocketMessage Clone() => MemberwiseClone() as ISocketMessage;
} }
} }

Loading…
Cancel
Save