Skip to content

Commit

Permalink
[ci skip] Updated documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
Emzi0767 committed Nov 28, 2017
1 parent a3bdefe commit a7d9102
Show file tree
Hide file tree
Showing 26 changed files with 280 additions and 59 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 1,7 @@
![Logo of DSharpPlus](https://github.com/NaamloosDT/DSharpPlus/raw/master/logo/dsharp _smaller.png)

# DSharpPlus
A C# library for Discord based off [DiscordSharp](https://github.com/suicvne/DiscordSharp), but rewritten to fit the API standards
An unofficial .NET wrapper for the Discord API, based off [DiscordSharp](https://github.com/suicvne/DiscordSharp), but rewritten to fit the API standards

[![Build Status](https://img.shields.io/appveyor/ci/Emzi0767/dsharpplus-6g6vr/master.svg)](https://ci.appveyor.com/project/Emzi0767/dsharpplus-6g6vr/branch/master)
[![Discord Server](https://img.shields.io/discord/379378609942560770.svg?label=discord)](https://discord.gg/KeAS3pU)
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 15,7 @@ Then just select **Latest prerelease** version of DSharpPlus packages, and insta

You might need to restart Visual Studio for changes to take effect.

If you find any problems in the MyGet versions of the packages, please follow the instructions in [Reporting issues](/articles/issues.html)
If you find any problems in the MyGet versions of the packages, please follow the instructions in [Reporting issues](/articles/advanced/reporting_issues.html)
article.

## But I'm running GNU/Linux, Mac OS X, or BSD!
Expand Down
File renamed without changes.
File renamed without changes.
83 changes: 83 additions & 0 deletions docs/articles/commands/argument_converters.md
Original file line number Diff line number Diff line change
@@ -0,0 1,83 @@
# Augmenting commands - custom argument converters

Suppose you want to augment an existing argument converter, or introduce a new one. The Argument Converter system in
CommandsNext allows you to modify or register converters for arguments passed to commands. An argument converter for
type `T` is a class which implements @DSharpPlus.CommandsNext.Converters.IArgumentConverter`1 and has an
implementation for @DSharpPlus.CommandsNext.Converters.IArgumentConverter`1.TryConvert(System.String,DSharpPlus.CommandsNext.CommandContext,`0@) method.

Here's we'll be creating an augmented boolean converter.

## 1. Creating a converter

Create a new class, call it `EnhancedBoolConverter`, and make it implement @DSharpPlus.CommandsNext.Converters.IArgumentConverter`1
with generic argument set to bool (`IArgumentConverter<bool>`).

In the `TryConvert` method, you will want to add code which checks if the `value` is equal to `"yes"` or `"no"`, and return
appropriate value. Otherwise it should fallback to default bool parser. It should look more or less like this:

```cs
using System;
using System.Collections.Generic;
using System.Text;
using DSharpPlus.CommandsNext;
using DSharpPlus.CommandsNext.Converters;

namespace MyFirstBot
{
public class EnhancedBoolConverter : IArgumentConverter<bool>
{
public bool TryConvert(string value, CommandContext ctx, out bool result)
{
switch (value.ToLowerInvariant())
{
case "yes":
result = true;
return true;

case "no":
result = false;
return true;
}

return bool.TryParse(value, out result);
}
}
}
```

## 2. Registering the converter

Once your converter is created, you need to register it with CommandsNext. You can do that by invoking
@DSharpPlus.CommandsNext.CommandsNextExtension.RegisterConverter``1(IArgumentConverter{``0}) with the converter instance:

```cs
commands.RegisterConverter(new EnhancedBoolConverter());
```

You need to call the method before you register your commands.

## 3. Making use of the converter

Create a new command which takes a bool argument to test the converter:

```cs
[Command("yesno")]
public async Task YesNo(CommandContext ctx, bool arg)
{
await ctx.RespondAsync($"Your pick: {arg ? "Yes" : "No"}");
}
```

You can now invoke it as `;;yesno yes` or `;;yesno no`.

## 4. Further notes

This particular example replaces an existing converter with a new one. You can also register converters for other types
(including custom ones). All you need is a converter instance for it.

You can also give types a user-friendly name (that is used for help) by invoking the @DSharpPlus.CommandsNext.CommandsNextExtension.RegisterUserFriendlyTypeName``1(System.String)
method, e.g.:

```cs
commands.RegisterUserFriendlyTypeName<MyType>("my custom data");
```
85 changes: 85 additions & 0 deletions docs/articles/commands/dependency_injection.md
Original file line number Diff line number Diff line change
@@ -0,0 1,85 @@
# Dependency injection - passing data around

In a situation where you need to pass objects in and out of your command modules, you need a way to access that data.
Dependency injection provides a convenient and safe (not to mention the only correct) way of passing data to your
modules.

You use dependency injection by first creating a service provider, then supplying it to your @DSharpPlus.CommandsNext.CommandsNextConfiguration
instance via @DSharpPlus.CommandsNext.CommandsNextConfiguration.Services property. The objects you placed in the
service provider will then be injected into your modules when they are instantiated. During injection, CommandsNext
first injects objects via constructor (i.e. it will try to match any constructor parameter to service types in the
provider. If it fails, it will throw. Up next, any public writable properties are populated with services from the
provider. If a suitable service is not found, the property is not injected. The process is then repeated for public
writable fields. To prevent specific properties or fields from being injected, you can put the @DSharpPlus.CommandsNext.Attributes.DontInjectAttribute
over them.

This is useful in a scenario when you have any kind of data that you need to be persistent or accessible from command
modules, such as settings classes, entity framework database contexts, and so on.

## 1. Creating a service provider

If you go back to the basic CommandsNext example, you will remember the `random` command. Let's amend it, and make
use of shared `Random` instance (note that reusing `Random` instances is generally not a good idea; here it's done for
the sake of the example).

Before you enable your CommandsNext module, you will need to create a new `ServiceCollection` instance, then add a
singleton `Random` instance to it, and finally, build a service provider out of it. You can do it like so:

```cs
var deps = new ServiceCollection()
.AddSingleton(new Random())
.BuildServiceProvider();
```

Don't forget to add `using Microsoft.Extensions.DependencyInjection;` to your usings.

You then need to pass the resulting provider to your CommandsNext configuration. Amend it like so:

```cs
commands = discord.UseCommandsNext(new CommandsNextConfiguration
{
StringPrefix = ";;",
Services = deps
});
```

## 2. Amending the command module

Go to your command module, and give it a read-only property called Rng, of type Random:

```cs
public Random Rng { get; }
```

Now create a constructor for the module, which takes an instance of Random as an argument:

```cs
public MyCommands(Random rng)
{
Rng = rng;
}
```

And finally edit the `Random` command to look like this:

```cs
[Command("random")]
public async Task Random(CommandContext ctx, int min, int max)
{
await ctx.RespondAsync($"🎲 Your random number is: {Rng.Next(min, max)}");
}
```

When you invoke `;;random 1 10` now, it will use the shared `Random` instance.

## 3. Further notes

While the service collection can hold singletons, it can hold transient and scoped instances as well. The difference is
that singleton instances are instantantiated once (when added to the collection), scoped are instantiated once per
module instantiation, and transients are instantiated every time they are requested.

Combined with transient module lifespans, injecting an entity framework database context as a transient or scoped
service makes working with databases easier, as an example.

Note that if a module has singleton lifespan, all services will be injected to it once. Only transient modules take
advantage of scoped and transient services.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 8,7 @@ it will also make grabbing additional data for your commands easy.

Right now, your bot is console-mute. Let's change it. Let's make it output all information about its state and doings.

To do that, add the following options to your `DiscordConfig`:
To do that, add the following options to your `DiscordConfiguration`:

```cs
UseInternalLogHandler = true,
Expand All @@ -19,8 19,8 @@ LogLevel = LogLevel.Debug

Using the procedures in the previous article, install a NuGet package called `DSharpPlus.CommandsNext`.

Now you need to enable CommandsNext module on your DiscordClient. Add a new field to your bot's `Program` class:
`static CommandsNextModule commands;`
Now you need to enable CommandsNext extension on your DiscordClient. Add a new field to your bot's `Program` class:
`static CommandsNextExtension commands;`

Visual Studio will complain, you also need to add `using DSharpPlus.CommandsNext;` to your usings.

Expand Down Expand Up @@ -80,7 80,7 @@ namespace MyFirstBot
class Program
{
static DiscordClient discord;
static CommandsNextModule commands;
static CommandsNextExtension commands;

static void Main(string[] args)
{
Expand All @@ -89,7 89,7 @@ namespace MyFirstBot

static async Task MainAsync(string[] args)
{
discord = new DiscordClient(new DiscordConfig
discord = new DiscordClient(new DiscordConfiguration
{
Token = "<your token here>",
TokenType = TokenType.Bot,
Expand Down Expand Up @@ -194,7 194,7 @@ can convert to the following:
* Text and character types: `string`, `char`
* Boolean types: `bool`
* Date and time types: `DateTime`, `DateTimeOffset`, `TimeSpan`
* Discord entities: `DiscordGuild`, `DiscordChannel`, `DiscordMember`, `DiscordUser`, `DiscordRole`, `DiscordMessage`, `DiscordEmoji`
* Discord entities: `DiscordGuild`, `DiscordChannel`, `DiscordMember`, `DiscordUser`, `DiscordRole`, `DiscordMessage`, `DiscordEmoji`, `DiscordColor`

Using these is as simple as declaring additional arguments for your command function. Let's say you want to create a command
that generates a random number between the two specified numbers. You can do it by adding two `int` arguments to your function.
Expand All @@ -217,5 217,5 @@ and 10 exclusive.

## 6. Advanced subjects

Commands are covered more in-depth in [Emzi0767's Example bot #2](https://github.com/Emzi0767/DSharpPlus-Example-Bot/tree/master/DSPlus.Examples.CSharp.Ex02 "Example Bot #2"). If you want to check out all the cool things CommandsNext can
do to make your life easier, make sure to check it out.
Commands are covered more in-depth in [Emzi0767's Example bot #2](https://github.com/Emzi0767/DSharpPlus-Example-Bot/tree/master/DSPlus.Examples.CSharp.Ex02 "Example Bot #2").
If you want to check out all the cool things CommandsNext can do to make your life easier, make sure to check it out.
12 changes: 12 additions & 0 deletions docs/articles/commands/module_lifespans.md
Original file line number Diff line number Diff line change
@@ -0,0 1,12 @@
# Command module lifespans - preventing module reuse

There are situations where you don't want to reuse a module instance, for one reason or another, usually due to
thread-safety concerns.

CommandsNext allows command modules 2 have to lifespan modes: singleton (default), and transient. Singleton modules, as
the name implies, are instantiated once per the entire CNext extension's lifetime. Transient modules, on the other
hand, are instantiated for each command call. This enables you to make use of transient and scoped modules. If you're
unsure what that means, familiarize yourself with the [dependency injection](/articles/commands/dependency_injection.html "dependency injection")
guide.

## TODO
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 28,56 @@ If none of these fit your criteria, you can make your own implementation, using
First, you need to install the desired WebSocket client implementation. If you're installing from NuGet, the procedure is the
same as for all other DSharpPlus packages.

Then you need to indicate that DSharpPlus should use that specific WebSocket implementation. This is done by calling
@DSharpPlus.DiscordClient.SetWebSocketClient``1 method with appropriate generic argument right after you instantiate your
Discord client.
Then you need to indicate that DSharpPlus should use that specific WebSocket implementation. This is done by setting an
appropriate factory method in @DSharpPlus.DiscordConfiguration.WebSocketClientFactory property in your @DSharpPlus.DiscordConfiguration instance.

For example, for WS4Net client, you need to call it as:
The factory methods are static methods, that return an instance of @DSharpPlus.Net.WebSocket.BaseWebSocketClient, and take a `System.Net.IWebProxy`
as an argument. For provided implementations, they are called `CreateNew`, and are available on the implementation classes:

* WebSocket4Net: @DSharpPlus.Net.WebSocket.WebSocket4NetClient.CreateNew(IWebProxy)
* WebSocket4NetCore: @DSharpPlus.Net.WebSocket.WebSocket4NetCoreClient.CreateNew(IWebProxy)
* WebSocketSharp: @DSharpPlus.Net.WebSocket.WebSocketSharpClient.CreateNew(IWebProxy)

In order to use a specific implementation, you pass selected factory method to the aformentioned `WebSocketClientFactory` property.

For example, for WS4Net client, you need to set it like this:

```cs
client.SetWebSocketClient<WebSocket4NetClient>();
var config = new DiscordConfiguration
{
Token = "my.token.here",
TokenType = TokenType.Bot,
// yadda yadda
WebSocketClientFactory = WebSocket4NetClient.CreateNew
};
```

For WS4NetCore:

```cs
client.SetWebSocketClient<WebSocket4NetCoreClient>();
var config = new DiscordConfiguration
{
Token = "my.token.here",
TokenType = TokenType.Bot,
// yadda yadda
WebSocketClientFactory = WebSocket4NetCoreClient.CreateNew
};
```

Similarly, for WS#:

```cs
client.SetWebSocketClient<WebSocketSharpClient>();
var config = new DiscordConfiguration
{
Token = "my.token.here",
TokenType = TokenType.Bot,
// yadda yadda
WebSocketClientFactory = WebSocketSharpClient.CreateNew
};
```

For any other implementation, make sure it's a class that inherits from @DSharpPlus.Net.WebSocket.BaseWebSocketClient class
and has a public parameter-less constructor.
For any other implementation, make sure you have a class that inherits from @DSharpPlus.Net.WebSocket.BaseWebSocketClient class,
implements its abstract members, and has a public constructor which takes a `System.Net.IWebProxy` as an argument. Provide a factory
method which instantiates this implementation, and you're good to go.

Lastly, don't forget to add `using DSharpPlus.Net.WebSocket;` at the top of your `.cs` file.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 22,7 @@ IDEs (so long as they support .NET Core).
If you're using Windows 7, create a regular .NET Framework project (it's required you target at least .NET 4.5; we recommend
4.7).

Make sure you read the article about [Alternate WebSocket Client Implementations](/articles/alt_ws.html).
Make sure you read the article about [Alternate WebSocket Client Implementations](/articles/getting_started/alternate_ws.html).

## 1. Creating your project

Expand Down Expand Up @@ -166,7 166,7 @@ If this is the case, you are ready to move on.
Hit F5. This will compile your code and run the project. If all went well, your bot should now be online and respond to
messages that start with ping.

If you're a Windows 7 user, it won't work. Read the [Alternate WebSocket Client Implementations](/articles/alt_ws.html)
If you're a Windows 7 user, it won't work. Read the [Alternate WebSocket Client Implementations](/articles/getting_started/alternate_ws.html)
on ways to fix the issue.

![Step 9](/images/02_08_alive.png)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 60,4 @@ links.

## 6. Making it come online

Now that this is all completed, head over to [Basic bot](/articles/first_bot.html "Basic bot") to make the bot come online.
Now that this is all completed, head over to [Basic bot](/articles/getting_started/basic_bot.html "Basic bot") to make the bot come online.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 53,7 @@ Task MyEventHandlerMethod()
## Parameterized event handlers

This is largely similar to parameter-less, except these event handlers take appropriate `EventArgs`, that are derived from
[DiscordEventArgs class](/api/DSharpPlus.EventArgs.DiscordEventArgs.html).
@DSharpPlus.EventArgs.DiscordEventArgs.

```cs
discord.MessageCreated = async e =>
Expand Down Expand Up @@ -82,3 82,9 @@ Task MyEventHandlerMethod()
return Task.CompletedTask; // or Task.Delay(0); if targeting .NET 4.5.x
}
```

## Preventing further event handlers from running

Parametrized asynchronous events take instances that derive from @DSharpPlus.AsyncEventArgs. This means they
have a @DSharpPlus.AsyncEventArgs.Handled property, which, if set to `true` prevents further event handlers
from executing.
Original file line number Diff line number Diff line change
@@ -1,7 1,7 @@
# Halp! I tried ~~hard drugs~~ Mono and my bot crashes on start!

Mono is an open-source implementation of the .NET Framework for non-Windows operating systems. However, it has a large
share of flaws, some of which break support for DSharpPlus without extra effort. It is generally recommended you stay
number of flaws, some of which break support for DSharpPlus without extra effort. It is generally recommended you stay
away from it.

## But I cannot use Windows! What do?
Expand Down Expand Up @@ -37,7 37,7 @@ Mono lacks support for most of the HTTP-related code from .NETFX Base Class Libr
you install an alternative WebSocket client implementation.

To achieve that, follow the instructions outlined in the
[Alternate WebSocket client implementations](/articles/alt_ws.html "Alternate WebSocket client implementations")
[Alternate WebSocket client implementations](/articles/getting_started/alternate_ws.html "Alternate WebSocket client implementations")
section of the guide.

### Place validation callback override in your code
Expand Down
Loading

0 comments on commit a7d9102

Please sign in to comment.