Browse Source

Merged changed from dev branch

tags/1.0-rc
RogueException 8 years ago
parent
commit
683f0d5013
19 changed files with 167 additions and 64 deletions
  1. +14
    -0
      Discord.Net.sln
  2. +15
    -0
      docs/CONTRIBUTING.md
  3. +6
    -6
      docs/guides/samples/module.cs
  4. +2
    -2
      docs/migrating.md
  5. +18
    -0
      src/Discord.Net.Commands/Attributes/PriorityAttribute.cs
  6. +3
    -3
      src/Discord.Net.Commands/Attributes/RemarksAttribute.cs
  7. +1
    -1
      src/Discord.Net.Commands/Attributes/SummaryAttribute.cs
  8. +18
    -6
      src/Discord.Net.Commands/Command.cs
  9. +2
    -0
      src/Discord.Net.Commands/CommandParser.cs
  10. +1
    -1
      src/Discord.Net.Commands/CommandService.cs
  11. +8
    -7
      src/Discord.Net.Commands/Map/CommandMap.cs
  12. +3
    -2
      src/Discord.Net.Commands/Map/CommandMapNode.cs
  13. +9
    -9
      src/Discord.Net.Commands/Module.cs
  14. +13
    -0
      src/Discord.Net.Core/Format.cs
  15. +8
    -1
      src/Discord.Net.WebSocket/DiscordSocketClient.cs
  16. +2
    -1
      src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
  17. +7
    -6
      src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs
  18. +3
    -4
      src/Discord.Net.WebSocket/project.json
  19. +34
    -15
      src/Discord.Net/project.json

+ 14
- 0
Discord.Net.sln View File

@@ -19,6 +19,10 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Discord.Net.Utils", "src\Di
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Rest", "src\Discord.Net.Rest\Discord.Net.Rest.xproj", "{BFC6DC28-0351-4573-926A-D4124244C04F}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.WebSocket", "src\Discord.Net.WebSocket\Discord.Net.WebSocket.xproj", "{22AB6C66-536C-4AC2-BBDB-A8BC4EB6B14D}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Rpc", "src\Discord.Net.Rpc\Discord.Net.Rpc.xproj", "{5688A353-121E-40A1-8BFA-B17B91FB48FB}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Discord.Net.Utils\Discord.Net.Utils.projitems*{2b75119c-9893-4aaa-8d38-6176eeb09060}*SharedItemsImports = 13
@@ -40,11 +44,21 @@ Global
{BFC6DC28-0351-4573-926A-D4124244C04F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BFC6DC28-0351-4573-926A-D4124244C04F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BFC6DC28-0351-4573-926A-D4124244C04F}.Release|Any CPU.Build.0 = Release|Any CPU
{22AB6C66-536C-4AC2-BBDB-A8BC4EB6B14D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{22AB6C66-536C-4AC2-BBDB-A8BC4EB6B14D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{22AB6C66-536C-4AC2-BBDB-A8BC4EB6B14D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{22AB6C66-536C-4AC2-BBDB-A8BC4EB6B14D}.Release|Any CPU.Build.0 = Release|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5688A353-121E-40A1-8BFA-B17B91FB48FB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{BFC6DC28-0351-4573-926A-D4124244C04F} = {288C363D-A636-4EAE-9AC1-4698B641B26E}
{22AB6C66-536C-4AC2-BBDB-A8BC4EB6B14D} = {288C363D-A636-4EAE-9AC1-4698B641B26E}
{5688A353-121E-40A1-8BFA-B17B91FB48FB} = {288C363D-A636-4EAE-9AC1-4698B641B26E}
EndGlobalSection
EndGlobal

+ 15
- 0
docs/CONTRIBUTING.md View File

@@ -0,0 +1,15 @@
# Contributing to Docs

I don't really have any strict conditions for writing documentation, but just keep these few guidelines in mind:

* Keep code samples in the `guides/samples` folder
* When referencing an object in the API, link to it's page in the API documentation.
* Documentation should be written in clear and proper English*

\* If anyone is interested in translating documentation into other languages, please open an issue or contact me on Discord (`foxbot#0282`).

### Compiling

Documentation is compiled into a static site using [DocFx](dotnet.github.io/docfx/). You **must** install a version of DocFx that supports .NET Core. The latest build of that is [2.1.0-cli-alpha](https://github.com/dotnet/docfx/releases/tag/v2.1.0-cli-alpha).

After making changes, compile your changes into the static site with `docfx`. You can also view your changes live with `docfx --serve`.

+ 6
- 6
docs/guides/samples/module.cs View File

@@ -6,9 +6,9 @@ using Discord.WebSocket;
public class Info
{
// ~say hello -> hello
[Command("say"), Description("Echos a message.")]
[Command("say"), Summary("Echos a message.")]
public async Task Say(IUserMessage msg,
[Unparsed, Description("The text to echo")] string echo)
[Unparsed, Summary("The text to echo")] string echo)
{
await msg.Channel.SendMessageAsync(echo);
}
@@ -19,9 +19,9 @@ public class Info
public class Sample
{
// ~sample square 20 ->
[Command("square"), Description("Squares a number.")]
[Command("square"), Summary("Squares a number.")]
public async Task Square(IUserMessage msg,
[Description("The number to square.")] int num)
[Summary("The number to square.")] int num)
{
await msg.Channel.SendMessageAsync($"{num}^2 = {Math.Pow(num, 2)}");
}
@@ -32,10 +32,10 @@ public class Sample
// ~sample userinfo Khionu --> Khionu#8708
// ~sample userinfo 96642168176807936 --> Khionu#8708
// ~sample whois 96642168176807936 --> Khionu#8708
[Command("userinfo"), Description("Returns info about the current user, or the user parameter, if one passed.")]
[Command("userinfo"), Summary("Returns info about the current user, or the user parameter, if one passed.")]
[Alias("user", "whois")]
public async Task UserInfo(IUserMessage msg,
[Description("The (optional) user to get info for")] IUser user = null)
[Summary("The (optional) user to get info for")] IUser user = null)
{
var userInfo = user ?? await Program.Client.GetCurrentUserAsync();
await msg.Channel.SendMessageAsync($"{userInfo.Username}#{userInfo.Discriminator}");


+ 2
- 2
docs/migrating.md View File

@@ -1,6 +1,6 @@
# Migrating from 0.9

**1.0.0 is the biggest breaking change the library has gone through, do to massive
**1.0.0 is the biggest breaking change the library has gone through, due to massive
changes in the design of the library.**

>A medium to advanced understanding is recommended when working with this library.
@@ -78,4 +78,4 @@ provide java-esque, synchronus `GetXXX` methods to replace the asynchronus metho
This functionality may be changed at a later date, we are currently reviewing this implementation and
alternative methods.

For your reference, you may want to look through the extension classes located in @Discord.WebSocket
For your reference, you may want to look through the extension classes located in @Discord.WebSocket

+ 18
- 0
src/Discord.Net.Commands/Attributes/PriorityAttribute.cs View File

@@ -0,0 +1,18 @@
using System;

namespace Discord.Commands
{
/// <summary> Sets priority of commands </summary>
[AttributeUsage(AttributeTargets.Method)]
public class PriorityAttribute : Attribute
{
/// <summary> The priority which has been set for the command </summary>
public int Priority { get; }

/// <summary> Creates a new <see cref="PriorityAttribute"/> with the given priority. </summary>
public PriorityAttribute(int priority)
{
Priority = priority;
}
}
}

src/Discord.Net.Commands/Attributes/DescriptionAttribute.cs → src/Discord.Net.Commands/Attributes/RemarksAttribute.cs View File

@@ -2,13 +2,13 @@

namespace Discord.Commands
{
// Full summary of method
// Extension of the Cosmetic Summary, for Groups, Commands, and Parameters
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class DescriptionAttribute : Attribute
public class RemarksAttribute : Attribute
{
public string Text { get; }

public DescriptionAttribute(string text)
public RemarksAttribute(string text)
{
Text = text;
}

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

@@ -2,7 +2,7 @@

namespace Discord.Commands
{
// Brief summary of method/module/parameter
// Cosmetic Summary, for Groups and Commands
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Parameter)]
public class SummaryAttribute : Attribute
{


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

@@ -21,9 +21,10 @@ namespace Discord.Commands
public MethodInfo Source { get; }
public Module Module { get; }
public string Name { get; }
public string Description { get; }
public string Summary { get; }
public string Remarks { get; }
public string Text { get; }
public int Priority { get; }
public bool HasVarArgs { get; }
public IReadOnlyList<string> Aliases { get; }
public IReadOnlyList<CommandParameter> Parameters { get; }
@@ -38,7 +39,15 @@ namespace Discord.Commands
_instance = instance;

Name = source.Name;
Text = groupPrefix + attribute.Text;

if (attribute.Text == null)
Text = groupPrefix;

if (groupPrefix != "")
groupPrefix += " ";

if (attribute.Text != null)
Text = groupPrefix + attribute.Text;

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

@@ -54,14 +63,17 @@ namespace Discord.Commands
if (nameAttr != null)
Name = nameAttr.Text;

var description = source.GetCustomAttribute<DescriptionAttribute>();
if (description != null)
Description = description.Text;

var summary = source.GetCustomAttribute<SummaryAttribute>();
if (summary != null)
Summary = summary.Text;

var remarksAttr = source.GetCustomAttribute<RemarksAttribute>();
if (remarksAttr != null)
Remarks = remarksAttr.Text;

var priorityAttr = source.GetCustomAttribute<PriorityAttribute>();
Priority = priorityAttr?.Priority ?? 0;

Parameters = BuildParameters(source);
HasVarArgs = Parameters.Count > 0 ? Parameters[Parameters.Count - 1].IsMultiple : false;
Preconditions = BuildPreconditions(source);


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

@@ -150,6 +150,8 @@ namespace Discord.Commands
for (int i = argList.Count; i < command.Parameters.Count; i++)
{
var param = command.Parameters[i];
if (param.IsMultiple)
continue;
if (!param.IsOptional)
return ParseResult.FromError(CommandError.BadArgCount, "The input text has too few parameters.");
argList.Add(TypeReaderResult.FromSuccess(param.DefaultValue));


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

@@ -180,7 +180,7 @@ namespace Discord.Commands
public SearchResult Search(IUserMessage message, string input)
{
string lowerInput = input.ToLowerInvariant();
var matches = _map.GetCommands(input).ToImmutableArray();
var matches = _map.GetCommands(input).OrderByDescending(x => x.Priority).ToImmutableArray();
if (matches.Length > 0)
return SearchResult.FromSuccess(input, matches);


+ 8
- 7
src/Discord.Net.Commands/Map/CommandMap.cs View File

@@ -7,6 +7,7 @@ namespace Discord.Commands
internal class CommandMap
{
static readonly char[] _whitespaceChars = new char[] { ' ', '\r', '\n' };
private readonly object _lockObj = new object();

private readonly ConcurrentDictionary<string, CommandMapNode> _nodes;

@@ -23,11 +24,11 @@ namespace Discord.Commands
string name;

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

lock (this)
lock (_lockObj)
{
var nextNode = _nodes.GetOrAdd(name, x => new CommandMapNode(x));
nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command);
@@ -42,11 +43,11 @@ namespace Discord.Commands
string name;

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

lock (this)
lock (_lockObj)
{
CommandMapNode nextNode;
if (_nodes.TryGetValue(name, out nextNode))
@@ -69,7 +70,7 @@ namespace Discord.Commands
else
name = text.Substring(0, nextSpace);

lock (this)
lock (_lockObj)
{
CommandMapNode nextNode;
if (_nodes.TryGetValue(name, out nextNode))


+ 3
- 2
src/Discord.Net.Commands/Map/CommandMapNode.cs View File

@@ -8,6 +8,7 @@ namespace Discord.Commands
{
private readonly ConcurrentDictionary<string, CommandMapNode> _nodes;
private readonly string _name;
private readonly object _lockObj = new object();
private ImmutableArray<Command> _commands;

public bool IsEmpty => _commands.Length == 0 && _nodes.Count == 0;
@@ -24,7 +25,7 @@ namespace Discord.Commands
int nextSpace = text.IndexOf(' ', index);
string name;

lock (this)
lock (_lockObj)
{
if (text == "")
_commands = _commands.Add(command);
@@ -45,7 +46,7 @@ namespace Discord.Commands
int nextSpace = text.IndexOf(' ', index);
string name;

lock (this)
lock (_lockObj)
{
if (text == "")
_commands = _commands.Remove(command);


+ 9
- 9
src/Discord.Net.Commands/Module.cs View File

@@ -13,7 +13,7 @@ namespace Discord.Commands
public string Name { get; }
public string Prefix { get; }
public string Summary { get; }
public string Description { get; }
public string Remarks { get; }
public IEnumerable<Command> Commands { get; }
internal object Instance { get; }

@@ -35,9 +35,9 @@ namespace Discord.Commands
if (summaryAttr != null)
Summary = summaryAttr.Text;

var descriptionAttr = source.GetCustomAttribute<DescriptionAttribute>();
if (descriptionAttr != null)
Description = descriptionAttr.Text;
var remarksAttr = source.GetCustomAttribute<RemarksAttribute>();
if (remarksAttr != null)
Remarks = remarksAttr.Text;

List<Command> commands = new List<Command>();
SearchClass(source, instance, commands, Prefix, dependencyMap);
@@ -48,8 +48,6 @@ namespace Discord.Commands

private void SearchClass(TypeInfo parentType, object instance, List<Command> commands, string groupPrefix, IDependencyMap dependencyMap)
{
if (groupPrefix != "")
groupPrefix += " ";
foreach (var method in parentType.DeclaredMethods)
{
var cmdAttr = method.GetCustomAttribute<CommandAttribute>();
@@ -62,10 +60,12 @@ namespace Discord.Commands
if (groupAttrib != null)
{
string nextGroupPrefix;
if (groupAttrib.Prefix != null)
nextGroupPrefix = groupPrefix + groupAttrib.Prefix ?? type.Name;

if (groupPrefix != "")
nextGroupPrefix = groupPrefix + " " + (groupAttrib.Prefix ?? type.Name.ToLowerInvariant());
else
nextGroupPrefix = groupPrefix;
nextGroupPrefix = groupAttrib.Prefix ?? type.Name.ToLowerInvariant();

SearchClass(type, ReflectionUtils.CreateObject(type, Service, dependencyMap), commands, nextGroupPrefix, dependencyMap);
}
}


+ 13
- 0
src/Discord.Net.Core/Format.cs View File

@@ -2,6 +2,9 @@
{
public static class Format
{
// Characters which need escaping
private static string[] SensitiveCharacters = { "*", "_", "~", "`", "\\" };

/// <summary> Returns a markdown-formatted string with bold formatting. </summary>
public static string Bold(string text) => $"**{text}**";
/// <summary> Returns a markdown-formatted string with italics formatting. </summary>
@@ -19,5 +22,15 @@
else
return $"`{text}`";
}

/// <summary> Sanitizes the string, safely escaping any Markdown sequences. </summary>
public static string Sanitize(string text)
{
foreach (string unsafeChar in SensitiveCharacters)
{
text = text.Replace(unsafeChar, $"\\{unsafeChar}");
}
return text;
}
}
}

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

@@ -38,7 +38,7 @@ namespace Discord.WebSocket
private int _nextAudioId;
private bool _canReconnect;

/// <summary> Gets the shard if of this client. </summary>
/// <summary> Gets the shard of of this client. </summary>
public int ShardId { get; }
/// <summary> Gets the current connection state of this client. </summary>
public ConnectionState ConnectionState { get; private set; }
@@ -793,6 +793,7 @@ namespace Discord.WebSocket
if (guild != null)
{
guild.AddChannel(data, DataStore);
channel = guild.AddChannel(data, DataStore);

if (!guild.IsSynced)
{
@@ -1263,6 +1264,12 @@ namespace Discord.WebSocket
}
if (after != null)
await _messageUpdatedEvent.InvokeAsync(Optional.Create(before), after).ConfigureAwait(false);
{
if (before != null)
await _messageUpdatedEvent.InvokeAsync(Optional.Create<IMessage>(before), after).ConfigureAwait(false);
else
await _messageUpdatedEvent.InvokeAsync(Optional.Create<IMessage>(), after).ConfigureAwait(false);
}
}
else
{


+ 2
- 1
src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs View File

@@ -148,11 +148,12 @@ namespace Discord.WebSocket

public override Task<IGuildChannel> GetChannelAsync(ulong id) => Task.FromResult<IGuildChannel>(GetChannel(id));
public override Task<IReadOnlyCollection<IGuildChannel>> GetChannelsAsync() => Task.FromResult<IReadOnlyCollection<IGuildChannel>>(Channels);
public void AddChannel(ChannelModel model, DataStore dataStore, ConcurrentHashSet<ulong> channels = null)
public ISocketGuildChannel AddChannel(ChannelModel model, DataStore dataStore, ConcurrentHashSet<ulong> channels = null)
{
var channel = ToChannel(model);
(channels ?? _channels).TryAdd(model.Id);
dataStore.AddChannel(channel);
return channel;
}
public ISocketGuildChannel GetChannel(ulong id)
{


+ 7
- 6
src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs View File

@@ -8,6 +8,7 @@ namespace Discord.WebSocket
internal class SocketGlobalUser : User, ISocketUser
{
internal override bool IsAttached => true;
private readonly object _lockObj = new object();

private ushort _references;

@@ -25,13 +26,13 @@ namespace Discord.WebSocket
{
checked
{
lock (this)
lock (_lockObj)
_references++;
}
}
public void RemoveRef(DiscordSocketClient discord)
{
lock (this)
lock (_lockObj)
{
if (--_references == 0)
discord.RemoveUser(Id);
@@ -40,16 +41,16 @@ namespace Discord.WebSocket

public override void Update(Model model)
{
lock (this)
lock (_lockObj)
base.Update(model, source);
}
public void Update(PresenceModel model)
{
//Race conditions are okay here. Multiple shards racing already cant guarantee presence in order.
//lock (this)
//lock (_lockObj)
//{
var game = model.Game != null ? new Game(model.Game) : null;
var game = model.Game != null ? new Game(model.Game) : null;
Presence = new Presence(game, model.Status);
//}
}


+ 3
- 4
src/Discord.Net.WebSocket/project.json View File

@@ -1,11 +1,10 @@
{
"version": "1.0.0-*",
"version": "1.0.0-beta2-*",

"buildOptions": {
"compile": {
"include": [ "../Discord.Net.Entities/**.cs", "../Discord.Net.Utils/**.cs" ]
},
"define": [ "WEBSOCKET" ]
"include": [ "../Discord.Net.Utils/**.cs" ]
}
},

"dependencies": {


+ 34
- 15
src/Discord.Net/project.json View File

@@ -1,6 +1,6 @@
{
"version": "1.0.0-beta2-*",
"description": "An aynchronous API wrapper for Discord using .NET. This package includes all of the optional Discord.Net components",
{
"version": "1.0.0-beta-*",
"description": "An unofficial .Net API wrapper for the Discord service.",
"authors": [ "RogueException" ],

"packOptions": {
@@ -13,19 +13,38 @@
}
},

"dependencies": {
"Discord.Net.Rest": {
"target": "project"
"buildOptions": {
"allowUnsafe": true,
"warningsAsErrors": false,
"xmlDoc": true
},

"configurations": {
"Release": {
"buildOptions": {
"define": [ "RELEASE" ],
"nowarn": [ "CS1573", "CS1591" ],
"optimize": true
}
}
//"Discord.Net.WebSocket": {
// "target": "project"
//},
//"Discord.Net.Rpc": {
// "target": "project"
//},
//"Discord.Net.Commands": {
// "target": "project"
//}
},

"dependencies": {
"Microsoft.Win32.Primitives": "4.0.1",
"Newtonsoft.Json": "8.0.3",
"System.Collections.Concurrent": "4.0.12",
"System.Collections.Immutable": "1.2.0",
"System.IO.Compression": "4.1.0",
"System.IO.FileSystem": "4.0.1",
"System.Net.Http": "4.1.0",
"System.Net.NameResolution": "4.0.0",
"System.Net.Sockets": "4.1.0",
"System.Net.WebSockets.Client": "4.0.0",
"System.Reflection.Extensions": "4.0.1",
"System.Runtime.InteropServices": "4.1.0",
"System.Runtime.InteropServices.RuntimeInformation": "4.0.0",
"System.Runtime.Serialization.Primitives": "4.1.1",
"System.Text.RegularExpressions": "4.1.0"
},

"frameworks": {


Loading…
Cancel
Save