From 5ad63563c16883fda9a89637f0b6b914fad4586d Mon Sep 17 00:00:00 2001 From: RogueException Date: Mon, 13 Jun 2016 20:06:44 -0300 Subject: [PATCH] Added initial commands project --- Discord.Net.sln | 6 + .../Attributes/CommandAttribute.cs | 14 +++ .../Attributes/DescriptionAttribute.cs | 14 +++ .../Attributes/GroupAttribute.cs | 14 +++ .../Attributes/ModuleAttribute.cs | 9 ++ .../Attributes/UnparsedAttribute.cs | 9 ++ src/Discord.Net.Commands/CommandParser.cs | 106 ++++++++++++++++++ .../Discord.Net.Commands.xproj | 19 ++++ src/Discord.Net.Commands/project.json | 34 ++++++ 9 files changed, 225 insertions(+) create mode 100644 src/Discord.Net.Commands/Attributes/CommandAttribute.cs create mode 100644 src/Discord.Net.Commands/Attributes/DescriptionAttribute.cs create mode 100644 src/Discord.Net.Commands/Attributes/GroupAttribute.cs create mode 100644 src/Discord.Net.Commands/Attributes/ModuleAttribute.cs create mode 100644 src/Discord.Net.Commands/Attributes/UnparsedAttribute.cs create mode 100644 src/Discord.Net.Commands/CommandParser.cs create mode 100644 src/Discord.Net.Commands/Discord.Net.Commands.xproj create mode 100644 src/Discord.Net.Commands/project.json diff --git a/Discord.Net.sln b/Discord.Net.sln index 804e73da8..11960606b 100644 --- a/Discord.Net.sln +++ b/Discord.Net.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net", "src\Discord.Net\Discord.Net.xproj", "{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Commands", "src\Discord.Net.Commands\Discord.Net.Commands.xproj", "{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|Any CPU.Build.0 = Debug|Any CPU {91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|Any CPU.ActiveCfg = Release|Any CPU {91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|Any CPU.Build.0 = Release|Any CPU + {078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Discord.Net.Commands/Attributes/CommandAttribute.cs b/src/Discord.Net.Commands/Attributes/CommandAttribute.cs new file mode 100644 index 000000000..e28017915 --- /dev/null +++ b/src/Discord.Net.Commands/Attributes/CommandAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace Discord.Commands +{ + [AttributeUsage(AttributeTargets.Method)] + public class CommandAttribute : Attribute + { + public string Name { get; } + public CommandAttribute(string name) + { + Name = name; + } + } +} diff --git a/src/Discord.Net.Commands/Attributes/DescriptionAttribute.cs b/src/Discord.Net.Commands/Attributes/DescriptionAttribute.cs new file mode 100644 index 000000000..736e9720b --- /dev/null +++ b/src/Discord.Net.Commands/Attributes/DescriptionAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace Discord.Commands +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter)] + public class DescriptionAttribute : Attribute + { + public string Text { get; } + public DescriptionAttribute(string text) + { + Text = text; + } + } +} diff --git a/src/Discord.Net.Commands/Attributes/GroupAttribute.cs b/src/Discord.Net.Commands/Attributes/GroupAttribute.cs new file mode 100644 index 000000000..a39437862 --- /dev/null +++ b/src/Discord.Net.Commands/Attributes/GroupAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace Discord.Commands +{ + [AttributeUsage(AttributeTargets.Class)] + public class GroupAttribute : Attribute + { + public string Name { get; } + public GroupAttribute(string name) + { + Name = name; + } + } +} diff --git a/src/Discord.Net.Commands/Attributes/ModuleAttribute.cs b/src/Discord.Net.Commands/Attributes/ModuleAttribute.cs new file mode 100644 index 000000000..5e9481a45 --- /dev/null +++ b/src/Discord.Net.Commands/Attributes/ModuleAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace Discord.Commands +{ + [AttributeUsage(AttributeTargets.Class)] + public class ModuleAttribute : Attribute + { + } +} diff --git a/src/Discord.Net.Commands/Attributes/UnparsedAttribute.cs b/src/Discord.Net.Commands/Attributes/UnparsedAttribute.cs new file mode 100644 index 000000000..9440b78af --- /dev/null +++ b/src/Discord.Net.Commands/Attributes/UnparsedAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace Discord.Commands +{ + [AttributeUsage(AttributeTargets.Parameter)] + public class UnparsedAttribute : Attribute + { + } +} diff --git a/src/Discord.Net.Commands/CommandParser.cs b/src/Discord.Net.Commands/CommandParser.cs new file mode 100644 index 000000000..adee2715b --- /dev/null +++ b/src/Discord.Net.Commands/CommandParser.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; + +namespace Discord.Commands +{ + public class Module + { + public string Name { get; } + public IEnumerable Commands { get; } + + internal Module(object module, TypeInfo typeInfo) + { + List commands = new List(); + SearchClass(commands); + Commands = commands; + } + + private void SearchClass(List commands) + { + //TODO: Implement + } + } + public class Command + { + public string SourceName { get; } + } + + public class CommandParser + { + private readonly SemaphoreSlim _moduleLock; + private readonly Dictionary _modules; + + public CommandParser() + { + _modules = new Dictionary(); + _moduleLock = new SemaphoreSlim(1, 1); + } + public async Task Load(object module) + { + await _moduleLock.WaitAsync().ConfigureAwait(false); + try + { + if (_modules.ContainsKey(module)) + throw new ArgumentException($"This module has already been loaded."); + return LoadInternal(module, module.GetType().GetTypeInfo()); + } + finally + { + _moduleLock.Release(); + } + } + private Module LoadInternal(object module, TypeInfo typeInfo) + { + var loadedModule = new Module(module, typeInfo); + _modules[module] = loadedModule; + return loadedModule; + } + public async Task> LoadAssembly(Assembly assembly) + { + List modules = new List(); + await _moduleLock.WaitAsync().ConfigureAwait(false); + try + { + foreach (var type in assembly.ExportedTypes) + { + var typeInfo = type.GetTypeInfo(); + if (typeInfo.GetCustomAttribute() != null) + { + var constructor = typeInfo.DeclaredConstructors.Where(x => x.GetParameters().Length == 0).FirstOrDefault(); + if (constructor == null) + throw new InvalidOperationException($"Failed to find a valid constructor for \"{typeInfo.FullName}\""); + object module; + try { module = constructor.Invoke(null); } + catch (Exception ex) + { + throw new InvalidOperationException($"Failed to create \"{typeInfo.FullName}\"", ex); + } + modules.Add(LoadInternal(module, typeInfo)); + } + } + return modules; + } + finally + { + _moduleLock.Release(); + } + } + + public async Task Unload(object module) + { + await _moduleLock.WaitAsync().ConfigureAwait(false); + try + { + return _modules.Remove(module); + } + finally + { + _moduleLock.Release(); + } + } + } +} diff --git a/src/Discord.Net.Commands/Discord.Net.Commands.xproj b/src/Discord.Net.Commands/Discord.Net.Commands.xproj new file mode 100644 index 000000000..597faf69c --- /dev/null +++ b/src/Discord.Net.Commands/Discord.Net.Commands.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 078dd7e6-943d-4d09-afc2-d2ba58b76c9c + Discord.Commands + .\obj + .\bin\ + v4.5.2 + + + 2.0 + + + \ No newline at end of file diff --git a/src/Discord.Net.Commands/project.json b/src/Discord.Net.Commands/project.json new file mode 100644 index 000000000..cff4b6ba5 --- /dev/null +++ b/src/Discord.Net.Commands/project.json @@ -0,0 +1,34 @@ +{ + "version": "1.0.0-dev", + "description": "A Discord.Net extension adding command support.", + "authors": [ "RogueException" ], + + "packOptions": { + "tags": [ "discord", "discordapp" ], + "licenseUrl": "http://opensource.org/licenses/MIT", + "projectUrl": "https://github.com/RogueException/Discord.Net", + "repository": { + "type": "git", + "url": "git://github.com/RogueException/Discord.Net" + } + }, + + "buildOptions": { + "allowUnsafe": true, + "warningsAsErrors": false + }, + + "dependencies": { + "Discord.Net": "1.0.0-dev" + }, + + "frameworks": { + "netstandard1.3": { + "imports": [ + "dotnet5.4", + "dnxcore50", + "portable-net45+win8" + ] + } + } +}