-
Notifications
You must be signed in to change notification settings - Fork 71
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
[Integration] Discord integration #244
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally it looks good.
Please ensure that there are not compiler warnings. I also added a lot of small comments.
{ | ||
var client = new DiscordClient(); | ||
|
||
client.LoginAsync(TokenType.Bot, botToken).Wait(ct); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Never, ever use Wait(). We can make an async version of the GetOrCreate method.
All methods of the client accept a RequestOption with cancellationToken. We should always forward that if possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, thank you so much!
Sadly the LoginAsync
method from DiscordRestClient
(or rather BaseDiscordClient
) from Discord.NET is a wrapper over the internal ApiClient.LoginAsync
method (this one accepts the RequestOptions parameter, which has a CancellationToken property). But the base function calls it with the default RequestOptions parameter.
Therefore, the problem is that the LoginAsync
function doesn't expose the RequestOptions
parameter (while other operations like e.g. SendMessage do expose it).
Technically I could write some kind of a workaround (e.g. WaitAsync
), but even if the cancellation token fires and WaitAsync completes, the LoginAsync Task will still get executed on that another thread. On the other hand, interrupting the Thread with it seems like overengineering and can lead to some integrity issues.
What do you think? Maybe I should just forget about the cancellation token in that specific method?
public string Text { get; set; } | ||
public string? DetailedBodyText { get; init; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add an extra line here. Why are you not just call it body btw: And Why do you need it? The text gives you the opportunity to actually control the formatting. Is it not superior?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, thank you!
Text is like subject, body is like content.
The Discord Embed messages allow you to set the title and then the body. If user doesn't provide the body, only the title is set.
{ | ||
var client = discordBotClientPool.GetDiscordClient(botToken, ct); | ||
|
||
var user = await client.GetUserAsync(ulong.Parse(chatId)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forward cancellation token.
backend/tests/Notifo.Domain.Tests/Integrations/Discord/DiscordTests.cs
Outdated
Show resolved
Hide resolved
backend/tests/Notifo.Domain.Tests/Integrations/Discord/DiscordTests.cs
Outdated
Show resolved
Hide resolved
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Notifo.Domain.Integrations.Discord; | ||
public sealed class DiscordTests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to have a custom base class as we have for the other providers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so since this is more likely an integration test that tests specific functionality related to my implementation. E.g. some other implementations from Messaging don't support images, links etc.
@@ -1,47 +1,51 @@ | |||
{ | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are all these changes? I think VS fucks up the formatting sometimes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw: now those formatting issues are fixed. You can't see it here in this commit, but if you compare it to the current version from the main branch, the indentation is similar.
Okay, thank you so much Sebastian! Will apply the changes soon and do all the other stuff I mentioned. I will be busy tomorrow, but I'll work on it later and let you know. Take care! |
Hey! Hope you're having a great day. After I get replies to my questions I wrote there, I'll push another commit with my changes. |
Just pushed the commit fixing those changes that you suggested. |
{ | ||
var client = new DiscordClient(); | ||
|
||
// Sadly it can't receive the cancellation token. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to write that much, nobody reads it. Just
"Method provides no option to pass CancellationToken" is enough
using Discord.Net; | ||
|
||
namespace Notifo.Domain.Integrations.Discord; | ||
public sealed partial class DiscordIntegration : IMessagingSender |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a new line after namespace declaration
} | ||
|
||
public async Task<DeliveryResult> SendAsync(IntegrationContext context, MessagingMessage message, | ||
CancellationToken ct) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please intend CancellationToken. See next method.
var client = await discordBotClientPool.GetDiscordClient(botToken, ct); | ||
var requestOptions = new RequestOptions { CancelToken = ct }; | ||
|
||
var user = await client.GetUserAsync(ulong.Parse(chatId), CacheMode.AllowDownload, requestOptions); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the Parse should be TryParse with a proper exception.
public Task<IntegrationStatus> OnConfiguredAsync(IntegrationContext context, IntegrationConfiguration? previous, | ||
CancellationToken ct) | ||
{ | ||
// Validate if the token is valid. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the comment for? It is weird!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should explain they why and not the what and should also not explain other methods from the same code base.
{ | ||
var userId = GetUserId(); | ||
|
||
var message = new MessagingMessage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They way you add extra lines is a little bit inconsistent here. I like this method, but other methods look different. Especially before "var message" and before "var result"
|
||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Notifo.Domain.Integrations.Discord; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check the namespace of other ServiceExtensions classes, I usually put them into "Microsoft.Extensions.DependencyInjection". it is a best practice to make it more discoverable and to void dozens and hundreds of usings in the Startup file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a few small change requests. Nothing serious, should take not more than 10 minutes to solve that.
Overall good work.
Thank you so much! I will apply those changes as soon as I find some time, have a nice day! |
Just pushed those changes |
#38
Hey! I finally finished building the Discord integration.
Can you please take a look at the code and review it?
Later on, I'd also like to add some additional features (e.g. configuration hints) for this (and other) integrations. Also, I'd work on writing some tests (as you mentioned). Furthermore, I noticed some additional bugs which I'd like to write the fixes to.
About this Discord integration itself, I modified the
MessagingMessage
since Discord allows us to send more sophisticated messages. For example, this is how the messages from the tests I wrote look like:they can also contain images, links, etc.
To obtain the bot token, you have to go onto the Discord Developer Platform, create an application, go to the Bot tab from the sidebar and get the token.
Also, to allow the bot to send you DMs, you have to install it on your Discord account (as we mentioned in #38 ). To do this, you first have to enable those installations on the bot.
Then, in Notifo, you can set the Discord user_id for the given user.
To learn how to find the user id on Discord, see this tutorial.
Have a great evening!