Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split IMessage into IUserMessage and ISystemMessage #237

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

An unofficial .Net API Wrapper for the Discord client (http://discordapp.com).

Check out the [documentation](http://rtd.discord.foxbot.me/en/docs-dev/index.html) or join the [Discord API Chat](https://discord.gg/0SBTUU1wZTVjAMPx).
Check out the [documentation](https://discord.foxbot.me/docs/) or join the [Discord API Chat](https://discord.gg/0SBTUU1wZTVjAMPx).

## Installation
### Stable (NuGet)
Expand Down
18 changes: 18 additions & 0 deletions src/Discord.Net.Commands/Attributes/AliasAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace Discord.Commands
{
/// <summary> Provides aliases for a command. </summary>
[AttributeUsage(AttributeTargets.Method)]
public class AliasAttribute : Attribute
{
/// <summary> The aliases which have been defined for the command. </summary>
public string[] Aliases { get; }

/// <summary> Creates a new <see cref="AliasAttribute"/> with the given aliases. </summary>
public AliasAttribute(params string[] aliases)
{
Aliases = aliases;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ namespace Discord.Commands
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public RequireContextAttribute(ContextType 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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public RequirePermissionAttribute(ChannelPermission permission)
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;

Expand Down
45 changes: 34 additions & 11 deletions src/Discord.Net.Commands/Command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class Command
private static readonly ConcurrentDictionary<Type, Func<IEnumerable<object>, object>> _arrayConverters = new ConcurrentDictionary<Type, Func<IEnumerable<object>, object>>();

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 Module Module { get; }
Expand All @@ -25,6 +25,7 @@ public class Command
public string Summary { get; }
public string Text { get; }
public bool HasVarArgs { get; }
public IReadOnlyList<string> Aliases { get; }
public IReadOnlyList<CommandParameter> Parameters { get; }
public IReadOnlyList<PreconditionAttribute> Preconditions { get; }

Expand All @@ -37,6 +38,16 @@ internal Command(MethodInfo source, Module module, object instance, CommandAttri
Name = source.Name;
Text = groupPrefix + attribute.Text;

var aliasesBuilder = ImmutableArray.CreateBuilder<string>();

aliasesBuilder.Add(Text);

var aliasesAttr = source.GetCustomAttribute<AliasAttribute>();
if (aliasesAttr != null)
aliasesBuilder.AddRange(aliasesAttr.Aliases.Select(x => groupPrefix + x));

Aliases = aliasesBuilder.ToImmutable();

var nameAttr = source.GetCustomAttribute<NameAttribute>();
if (nameAttr != null)
Name = nameAttr.Text;
Expand All @@ -55,7 +66,7 @@ internal Command(MethodInfo source, Module module, object instance, CommandAttri
_action = BuildAction(source);
}

public async Task<PreconditionResult> CheckPreconditions(IMessage context)
public async Task<PreconditionResult> CheckPreconditions(IUserMessage context)
{
foreach (PreconditionAttribute precondition in Module.Preconditions)
{
Expand All @@ -74,16 +85,28 @@ public async Task<PreconditionResult> CheckPreconditions(IMessage context)
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)
return ParseResult.FromError(searchResult);
if (preconditionResult != null && !preconditionResult.Value.IsSuccess)
return ParseResult.FromError(preconditionResult.Value);

return await CommandParser.ParseArgs(this, msg, searchResult.Text.Substring(Text.Length), 0).ConfigureAwait(false);
string input = searchResult.Text;
var matchingAliases = Aliases.Where(alias => input.StartsWith(alias));

string matchingAlias = "";
foreach (string alias in matchingAliases)
{
if (alias.Length > matchingAlias.Length)
matchingAlias = alias;
}

input = input.Substring(matchingAlias.Length);

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)
return Task.FromResult(ExecuteResult.FromError(parseResult));
Expand All @@ -104,13 +127,13 @@ public Task<ExecuteResult> Execute(IMessage msg, ParseResult parseResult)
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
{
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();
}
catch (Exception ex)
Expand All @@ -127,8 +150,8 @@ private IReadOnlyList<PreconditionAttribute> BuildPreconditions(MethodInfo metho
private IReadOnlyList<CommandParameter> BuildParameters(MethodInfo methodInfo)
{
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);
for (int i = 1; i < parameters.Length; i++)
Expand Down Expand Up @@ -167,7 +190,7 @@ private IReadOnlyList<CommandParameter> BuildParameters(MethodInfo methodInfo)
}
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))
throw new InvalidOperationException("Commands must return a non-generic Task.");
Expand Down
2 changes: 1 addition & 1 deletion src/Discord.Net.Commands/CommandParameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public CommandParameter(ParameterInfo source, string name, string summary, Type
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);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Discord.Net.Commands/CommandParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ private enum ParserPart
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;
StringBuilder argBuilder = new StringBuilder(input.Length);
Expand Down
13 changes: 7 additions & 6 deletions src/Discord.Net.Commands/CommandService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ public CommandService()
[typeof(DateTime)] = new SimpleTypeReader<DateTime>(),
[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(IDMChannel)] = new ChannelTypeReader<IDMChannel>(),
[typeof(IGroupChannel)] = new ChannelTypeReader<IGroupChannel>(),
Expand Down Expand Up @@ -175,8 +176,8 @@ private bool UnloadInternal(object module)
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();
var matches = _map.GetCommands(input).ToImmutableArray();
Expand All @@ -187,9 +188,9 @@ public SearchResult Search(IMessage message, string input)
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);
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);
if (!searchResult.IsSuccess)
Expand Down
6 changes: 3 additions & 3 deletions src/Discord.Net.Commands/Extensions/MessageExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
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;
if (text.Length > 0 && text[0] == c)
Expand All @@ -12,7 +12,7 @@ public static bool HasCharPrefix(this IMessage msg, char c, ref int argPos)
}
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;
if (text.StartsWith(str))
Expand All @@ -22,7 +22,7 @@ public static bool HasStringPrefix(this IMessage msg, string str, ref int argPos
}
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;
if (text.Length <= 3 || text[0] != '<' || text[1] != '@') return false;
Expand Down
54 changes: 29 additions & 25 deletions src/Discord.Net.Commands/Map/CommandMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,44 @@ public CommandMap()

public void AddCommand(Command command)
{
string text = command.Text;
int nextSpace = NextWhitespace(text);
string name;
foreach (string text in command.Aliases)
{
int nextSpace = NextWhitespace(text);
string name;

if (nextSpace == -1)
name = command.Text;
else
name = command.Text.Substring(0, nextSpace);
if (nextSpace == -1)
name = command.Text;
else
name = command.Text.Substring(0, nextSpace);

lock (this)
{
var nextNode = _nodes.GetOrAdd(name, x => new CommandMapNode(x));
nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command);
lock (this)
{
var nextNode = _nodes.GetOrAdd(name, x => new CommandMapNode(x));
nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command);
}
}
}
public void RemoveCommand(Command command)
{
string text = command.Text;
int nextSpace = NextWhitespace(text);
string name;
foreach (string text in command.Aliases)
{
int nextSpace = NextWhitespace(text);
string name;

if (nextSpace == -1)
name = command.Text;
else
name = command.Text.Substring(0, nextSpace);
if (nextSpace == -1)
name = command.Text;
else
name = command.Text.Substring(0, nextSpace);

lock (this)
{
CommandMapNode nextNode;
if (_nodes.TryGetValue(name, out nextNode))
lock (this)
{
nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command);
if (nextNode.IsEmpty)
_nodes.TryRemove(name, out nextNode);
CommandMapNode nextNode;
if (_nodes.TryGetValue(name, out nextNode))
{
nextNode.RemoveCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command);
if (nextNode.IsEmpty)
_nodes.TryRemove(name, out nextNode);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Discord.Net.Commands/Readers/ChannelTypeReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Discord.Commands
internal class ChannelTypeReader<T> : TypeReader
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;

Expand Down
2 changes: 1 addition & 1 deletion src/Discord.Net.Commands/Readers/EnumTypeReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public EnumTypeReader(Type type, TryParseDelegate<T> parser)
_enumsByValue = byValueBuilder.ToImmutable();
}

public override Task<TypeReaderResult> Read(IMessage context, string input)
public override Task<TypeReaderResult> Read(IUserMessage context, string input)
{
T baseValue;
object enumValue;
Expand Down
7 changes: 4 additions & 3 deletions src/Discord.Net.Commands/Readers/MessageTypeReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@

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;

//By Id (1.0)
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)
return Task.FromResult(TypeReaderResult.FromSuccess(msg));
}
Expand Down
2 changes: 1 addition & 1 deletion src/Discord.Net.Commands/Readers/RoleTypeReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Discord.Commands
internal class RoleTypeReader<T> : TypeReader
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;
ulong id;
Expand Down
2 changes: 1 addition & 1 deletion src/Discord.Net.Commands/Readers/SimpleTypeReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public SimpleTypeReader()
_tryParse = PrimitiveParsers.Get<T>();
}

public override Task<TypeReaderResult> Read(IMessage context, string input)
public override Task<TypeReaderResult> Read(IUserMessage context, string input)
{
T value;
if (_tryParse(input, out value))
Expand Down
2 changes: 1 addition & 1 deletion src/Discord.Net.Commands/Readers/TypeReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ namespace Discord.Commands
{
public abstract class TypeReader
{
public abstract Task<TypeReaderResult> Read(IMessage context, string input);
public abstract Task<TypeReaderResult> Read(IUserMessage context, string input);
}
}
2 changes: 1 addition & 1 deletion src/Discord.Net.Commands/Readers/UserTypeReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Discord.Commands
internal class UserTypeReader<T> : TypeReader
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 guild = (context.Channel as IGuildChannel)?.Guild;
Expand Down
2 changes: 0 additions & 2 deletions src/Discord.Net/API/Rest/GetChannelMessagesParams.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#pragma warning disable CS1591
using Discord.Rest;

namespace Discord.API.Rest
{
public class GetChannelMessagesParams
Expand Down
Loading