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

[Integration] Discord integration #244

Merged
merged 17 commits into from
Jun 30, 2024
Merged

Conversation

Arciiix
Copy link
Contributor

@Arciiix Arciiix commented Jun 25, 2024

#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:
example

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.

  1. Go to the Installation tab on the sidebar on the Developer Platform
  2. Check User install option in Authorization methods
  3. Select "Discord provided link" in Install link section
  4. Copy that link
  5. Open that link and select "Try it Now" (the first option)
  6. Authorize

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!

Copy link
Collaborator

@SebastianStehle SebastianStehle left a 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);
Copy link
Collaborator

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.

Copy link
Contributor Author

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; }
Copy link
Collaborator

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?

Copy link
Contributor Author

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));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forward cancellation token.

using Microsoft.Extensions.DependencyInjection;

namespace Notifo.Domain.Integrations.Discord;
public sealed class DiscordTests
Copy link
Collaborator

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?

Copy link
Contributor Author

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 @@
{

Copy link
Collaborator

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.

Copy link
Contributor Author

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.

@Arciiix
Copy link
Contributor Author

Arciiix commented Jun 25, 2024

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!

@Arciiix
Copy link
Contributor Author

Arciiix commented Jun 27, 2024

Hey! Hope you're having a great day.
I added some comments to your review. Once again thank you so much for your code review, it helps me write better code and be more helpful 🤗

After I get replies to my questions I wrote there, I'll push another commit with my changes.

@Arciiix
Copy link
Contributor Author

Arciiix commented Jun 28, 2024

Just pushed the commit fixing those changes that you suggested.
If you have some time, you can look at them and also at the comments under your comments on the code review.
Take care!

{
var client = new DiscordClient();

// Sadly it can't receive the cancellation token.
Copy link
Collaborator

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
Copy link
Collaborator

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)
Copy link
Collaborator

@SebastianStehle SebastianStehle Jun 30, 2024

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);
Copy link
Collaborator

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.
Copy link
Collaborator

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!

Copy link
Collaborator

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
Copy link
Collaborator

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;
Copy link
Collaborator

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.

Copy link
Collaborator

@SebastianStehle SebastianStehle left a 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.

@Arciiix
Copy link
Contributor Author

Arciiix commented Jun 30, 2024

Thank you so much! I will apply those changes as soon as I find some time, have a nice day!

@Arciiix
Copy link
Contributor Author

Arciiix commented Jun 30, 2024

Just pushed those changes

@SebastianStehle SebastianStehle merged commit d0db2df into notifo-io:main Jun 30, 2024
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants