Skip to content

Commit 44708e6

Browse files
author
Kaylee Sachs
authored
Merge pull request #67 from SahneeDEV/develop
Develop
2 parents ccc4812 + 2757d1a commit 44708e6

22 files changed

+270
-69
lines changed

README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,15 +144,18 @@ If hosting the bot yourself you will need to adjust the `appsettings.json` file:
144144
"BotSettings": {
145145
"IconUrl": "https://sahnee.dev/wp-content/uploads/2020/04/sahnee-bot-150x150.png",
146146
"Url": "https://sahnee.dev/en/project/sahnee-bot/",
147+
"GithubUrl": "https://github.com/SahneeDEV/sahnee-bot",
147148
"WarningRolePrefix": "warning: ",
148149
"WarningRoleColor": "#607D8B",
149150
"SupportServer": "https://discord.gg/FfVurUzVfE",
150151
"Changelog": "./CHANGELOG.md",
152+
"MaxChangelogsSendCount": "5",
151153
"ReleaseInformation": "./ReleaseInformation.txt",
152154
"InviteUrl": "https://discord.com/api/oauth2/authorize?client_id=689600370430836793&permissions=268627014&redirect_uri=https%3A%2F%2Fsahnee.dev%2Fen%2Fproject%2Fsahnee-bot%2F&scope=bot%20applications.commands",
153155
"ErrorWebhookUrl": "https://discord.com/api/webhooks/12345/abcde",
154156
"Jobs": {
155-
"CleanupWarningRoles": "1:00:00"
157+
"CleanupWarningRoles": "1:00:00",
158+
"UpdateGuildChangelog": "0:01:00"
156159
}
157160
}
158161
}
@@ -165,13 +168,25 @@ If hosting the bot yourself you will need to adjust the `appsettings.json` file:
165168
* `Discord:Implementation` - Allows you to set if you want to use the `Socket` or `Rest` discord API implementation. Don't change unless you know what you are doing and absolutely need it.
166169
* `BotSettings:IconUrl` - The icon of the bot used in messages.
167170
* `BotSettings:Url` - The homepage the bot links to.
171+
* `BotSettings:GithubUrl` - The source code page the bot links to.
168172
* `BotSettings:WarningRolePrefix` - The default prefix for warning roles of servers that have not configured their own.
169173
* `BotSettings:WarningRoleColor` - The default color for warning roles on a server.
170174
* `BotSettings:SupportServer` - A link to the support page for the bot.
171175
* `BotSettings:Changelog` - The path to the changelog file on disk. Will be scanned for a new version of bot startup.
176+
* `BotSettings:MaxChangelogsSendCount` - How many servers will be notified at once about a new version.
172177
* `BotSettings:ReleaseInformation` - A file that contains information about the release of the bot. Will be printed in the `/help` command.
173178
* `BotSettings:InviteUrl` - The invite URL users should use to invite the bot to their servers.
174179
* `BotSettings:ErrorWebhookUrl` - A webhook errors will be sent to.
175180
* `BotSettings:Jobs:CleanupWarningRoles` - The frequency in how often warnings created by the bot that are no longer used will be deleted.
181+
* `BotSettings:Jobs:UpdateGuildChangelog` - How often the bot will check if more servers need to be informed about a new version.
176182

177183
Time spans for jobs are formatted in the format documented [here](https://docs.microsoft.com/en-us/dotnet/api/system.timespan.parse?view=net-6.0#system-timespan-parse(system-string)) under the section "Remarks" (`[ws][-]{ d | [d.]hh:mm[:ss[.ff]] }[ws]`).
184+
185+
### Discord developer portal settings
186+
187+
* **Bot -> Privileged Gateway Intents**: `Presence Intent`, `Server Members Intent`
188+
* **OAuth2 -> General -> Redirects**: Add your redirect URL. In the example below `https://sahnee.dev/en/project/sahnee-bot/`
189+
* **Permissions**: When creating the invite URL the bot needs the following numeric permissions: `268627014`.
190+
* **Scopes**: The following scopes are required: `bot` and `application.commands`.
191+
192+
This for reference is the official invite URL: `https://discord.com/api/oauth2/authorize?client_id=689600370430836793&permissions=268627014&redirect_uri=https%3A%2F%2Fsahnee.dev%2Fen%2Fproject%2Fsahnee-bot%2F&scope=bot%20applications.commands`

SahneeBot/CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
1-
# CHANGELOG
1+
# CHANGELOG
2+
3+
## 1.0.3
4+
5+
Changelogs after a new update are now sent to only a few servers at a time instead of all at once (causing the Discord API to trigger a rate limit). This should reduce the flood of false error messages some servers got after a new update has been released.
6+
7+
## 1.1.0
8+
9+
- We updated some internally used libraries to communicate with Discord. This should overall fix some common errors.
10+
- We fixed an error in the warning cleanup job if a role without a name exists.
11+
- We updated the changelog distribution system to not overload the bot after each update when sending out all these changelogs to you folks! (hopefully)
12+
13+
Additionally, we are currently conducting a user survey about the Sahnee-Bot. We'd love for everyone to share their opinion, regardless of if you are a server admin, moderator or a normal user: https://click.sahnee.dev/UsEHTYOj - Thank you for your time! 🙂
214

315
## 1.0.2
416

SahneeBot/Commands/ChangelogCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Discord.Interactions;
22
using SahneeBot.Formatter;
3-
using SahneeBotController.Tasks;
3+
using SahneeBotController.Tasks.Changelog;
44

55
namespace SahneeBot.Commands;
66

SahneeBot/Events/ChangelogEvent.cs

Lines changed: 0 additions & 38 deletions
This file was deleted.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using Discord;
2+
using Microsoft.Extensions.Logging;
3+
using SahneeBotController;
4+
5+
namespace SahneeBot.Events;
6+
7+
/// <summary>
8+
/// The changelog event is called whenever a guild is available and posts the newest changelog.
9+
/// </summary>
10+
[Event]
11+
public class EnqueueGuildForChangelogEvent : EventBase<IGuild>
12+
{
13+
private readonly ILogger<EnqueueGuildForChangelogEvent> _logger;
14+
private readonly Bot _bot;
15+
private readonly GuildChangelogQueue _queue;
16+
17+
public EnqueueGuildForChangelogEvent(IServiceProvider serviceProvider
18+
, ILogger<EnqueueGuildForChangelogEvent> logger
19+
, Bot bot
20+
, GuildChangelogQueue queue) : base(serviceProvider)
21+
{
22+
_logger = logger;
23+
_bot = bot;
24+
_queue = queue;
25+
}
26+
27+
public override void Register()
28+
{
29+
_bot.Impl(socket => socket.GuildAvailable += Handle
30+
, rest =>
31+
throw new InvalidOperationException("The changelog event only support the socket client."));
32+
}
33+
34+
public override Task Handle(IGuild arg) => HandleAsync(ctx =>
35+
{
36+
_logger.LogDebug("Enqueue guild {Id} ({Name}) for the changelog event", arg.Id, arg.Name);
37+
_queue.Enqueue(arg.Id);
38+
return Task.FromResult<ISuccess>(new Success<bool>(true));
39+
}, new EventExecutionOptions
40+
{
41+
PlaceInQueue = arg.Id
42+
, RelatedGuildId = arg.Id
43+
, Name = "prepare new changelogs"
44+
, Debug = arg.Id.ToString()
45+
});
46+
}

SahneeBot/Formatter/DiscordFormat.cs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,25 @@ public delegate Task RespondAsyncDelegate(
114114
AllowedMentions? allowedMentions = null,
115115
RequestOptions? options = null,
116116
MessageComponent? components = null,
117-
Embed? embed = null);
117+
Embed? embed = null,
118+
MessageFlags flags = MessageFlags.None,
119+
ulong? threadId = null);
118120

119121
public delegate Task SendMessageAsyncDelegate(
120122
string? text = null,
121123
bool isTts = false,
124+
IEnumerable<Embed>? embeds = null,
125+
string? username = null,
126+
string? avatarUrl = null,
127+
RequestOptions? options = null,
128+
AllowedMentions? allowedMentions = null,
129+
MessageComponent? components = null,
130+
MessageFlags flags = MessageFlags.None,
131+
ulong? threadId = null);
132+
133+
public delegate Task SendUserMessageAsyncDelegate(
134+
string? text = null,
135+
bool isTtS = false,
122136
Embed? embed = null,
123137
RequestOptions? options = null,
124138
AllowedMentions? allowedMentions = null,
@@ -142,7 +156,8 @@ public delegate Task<IUserMessage> SendChannelMessageAsyncDelegate(
142156
MessageReference? messageReference = null,
143157
MessageComponent? components = null,
144158
ISticker[]? stickers = null,
145-
Embed[]? embeds = null);
159+
Embed[]? embeds = null,
160+
MessageFlags flags = MessageFlags.None);
146161

147162
public delegate Task<ulong> SendWebhookMessageAsyncDelegate(
148163
string? text = null,
@@ -163,14 +178,19 @@ await del(Text, Embeds?.Select(e => e.Build()).ToArray(), sendOptions.IsTts, sen
163178
}
164179
public async Task Send(SendMessageAsyncDelegate del, SendOptions sendOptions = default)
165180
{
166-
await del(Text, sendOptions.IsTts, Embed?.Build(), sendOptions.Request, AllowedMentions, Components?.Build(),
167-
Embeds?.Select(e => e.Build()).ToArray());
181+
await del(Text, sendOptions.IsTts, Embeds?.Select(e => e.Build()).ToArray(), "", string.Empty,
182+
sendOptions.Request, AllowedMentions, Components?.Build());
168183
}
169184
public async Task Send(SendChannelMessageAsyncDelegate del, SendOptions sendOptions = default)
170185
{
171186
await del(Text, sendOptions.IsTts, Embed?.Build(), sendOptions.Request, AllowedMentions, null,
172187
Components?.Build(), null, Embeds?.Select(e => e.Build()).ToArray());
173188
}
189+
public async Task Send(SendUserMessageAsyncDelegate del, SendOptions sendOptions = default)
190+
{
191+
await del(Text, sendOptions.IsTts, Embed?.Build(), sendOptions.Request, AllowedMentions,
192+
Components?.Build(), Embeds?.Select(e => e.Build()).ToArray());
193+
}
174194
public async Task Send(SendWebhookMessageAsyncDelegate del, SendOptions sendOptions = default)
175195
{
176196
var embeds = Embeds != null

SahneeBot/Formatter/HelpDiscordFormatter.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Discord;
2+
using Microsoft.Extensions.Configuration;
23

34
namespace SahneeBot.Formatter;
45

@@ -15,16 +16,19 @@ public record struct Args(ulong? GuildId, ulong? UserId);
1516
private readonly DefaultFormatArguments _defaultFormatArguments;
1617
private readonly Release _release;
1718
private readonly Changelog _changelog;
18-
private const string WEBSITE = "https://sahnee.dev/en/project/sahnee-bot/";
19-
private const string GITHUB = "https://github.com/Sahnee-DE/sahnee-bot";
19+
private readonly string _website;
20+
private readonly string _github;
2021

2122
public HelpDiscordFormatter(DefaultFormatArguments defaultFormatArguments
2223
, Release release
23-
, Changelog changelog)
24+
, Changelog changelog
25+
, IConfiguration configuration)
2426
{
2527
_defaultFormatArguments = defaultFormatArguments;
2628
_release = release;
2729
_changelog = changelog;
30+
_website = configuration["BotSettings:Url"];
31+
_github = configuration["BotSettings:GithubUrl"];
2832
}
2933

3034
public Task<DiscordFormat> Format(Args arg)
@@ -36,13 +40,13 @@ public Task<DiscordFormat> Format(Args arg)
3640
new()
3741
{
3842
Name = "Website of the bot",
39-
Value = WEBSITE,
43+
Value = _website,
4044
IsInline = true
4145
},
4246
new()
4347
{
4448
Name = "GitHub Repository of the bot",
45-
Value = GITHUB,
49+
Value = _github,
4650
IsInline = true
4751
},
4852
new()

SahneeBot/Formatter/IDiscordFormatter.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ public static async Task FormatAndSend<T>(this IDiscordFormatter<T> discordForma
4747
var format = await discordFormatter.Format(arg);
4848
await format.Send(del, sendOptions);
4949
}
50+
public static async Task FormatAndSend<T>(this IDiscordFormatter<T> discordFormatter, T arg,
51+
DiscordFormat.SendUserMessageAsyncDelegate del, DiscordFormat.SendOptions sendOptions = default)
52+
{
53+
var format = await discordFormatter.Format(arg);
54+
await format.Send(del, sendOptions);
55+
}
5056
public static async Task FormatAndSend<T>(this IDiscordFormatter<T> discordFormatter, T arg,
5157
DiscordFormat.SendWebhookMessageAsyncDelegate del, DiscordFormat.SendOptions sendOptions = default)
5258
{
@@ -125,6 +131,25 @@ public static async Task<bool> SendMany(this IEnumerable<DiscordFormat> formats
125131
return sentAny;
126132
}
127133

134+
public static async Task<bool> SendMany(this IEnumerable<DiscordFormat> formats
135+
, DiscordFormat.SendUserMessageAsyncDelegate del
136+
, DiscordFormat.SendOptions sendOptions = default
137+
, Func<Task>? beforeSendFirst = null)
138+
{
139+
var sentAny = false;
140+
foreach (var format in formats)
141+
{
142+
if (!sentAny && beforeSendFirst != null)
143+
{
144+
await beforeSendFirst();
145+
}
146+
await format.Send(del, sendOptions);
147+
sentAny = true;
148+
}
149+
150+
return sentAny;
151+
}
152+
128153
public static async Task<bool> SendMany(this IEnumerable<DiscordFormat> formats
129154
, DiscordFormat.SendMessageAsyncDelegate del
130155
, DiscordFormat.SendOptions sendOptions = default

SahneeBot/GuildChangelogQueue.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System.Collections.Concurrent;
2+
3+
namespace SahneeBot;
4+
5+
/// <summary>
6+
/// The queue for guilds that should be checked for changelogs.
7+
/// </summary>
8+
public class GuildChangelogQueue
9+
{
10+
private readonly ConcurrentQueue<ulong> _queue = new();
11+
12+
/// <summary>
13+
/// Enqueues a guild ID.
14+
/// </summary>
15+
/// <param name="guildId">The guild ID.</param>
16+
public void Enqueue(ulong guildId)
17+
{
18+
_queue.Enqueue(guildId);
19+
}
20+
21+
/// <summary>
22+
/// Tries to dequeue a guild ID.
23+
/// </summary>
24+
/// <param name="guildId">The guild ID, only valid is true is returned.</param>
25+
/// <returns>If an ID could be dequeued.</returns>
26+
public bool TryDequeue(out ulong guildId)
27+
{
28+
return _queue.TryDequeue(out guildId);
29+
}
30+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using Microsoft.Extensions.Configuration;
2+
using Microsoft.Extensions.Logging;
3+
using SahneeBotController.Tasks.Changelog;
4+
5+
namespace SahneeBot.Jobs;
6+
7+
/// <summary>
8+
/// This job sends changelogs to guilds that do not have them yet in regular intervals.
9+
/// </summary>
10+
[Job]
11+
public sealed class SendChangelogsJob : JobBase {
12+
private readonly ILogger<SendChangelogsJob> _logger;
13+
private readonly GuildChangelogQueue _queue;
14+
private readonly Bot _bot;
15+
private readonly UpdateGuildChangelogTask _updateGuildChangelogTask;
16+
private readonly uint _maxChangelogsSendCount;
17+
18+
public SendChangelogsJob(IServiceProvider serviceProvider
19+
, ILogger<SendChangelogsJob> logger
20+
, GuildChangelogQueue queue
21+
, IConfiguration cfg
22+
, Bot bot
23+
, UpdateGuildChangelogTask updateGuildChangelogTask) : base(serviceProvider) {
24+
_logger = logger;
25+
_queue = queue;
26+
_bot = bot;
27+
_updateGuildChangelogTask = updateGuildChangelogTask;
28+
_maxChangelogsSendCount = uint.Parse(cfg["BotSettings:MaxChangelogsSendCount"]);
29+
Time = new JobTimeSpanRepeat(TimeSpan.Parse(cfg["BotSettings:Jobs:UpdateGuildChangelog"]));
30+
}
31+
32+
public override async Task Perform() {
33+
_logger.LogDebug(EventIds.Jobs, "Starting changelogs job");
34+
35+
uint sentChangelogs = 0;
36+
while (sentChangelogs < _maxChangelogsSendCount && _queue.TryDequeue(out var guildId))
37+
{
38+
var guild = await _bot.Client.GetGuildAsync(guildId);
39+
if (guild == null)
40+
{
41+
_logger.LogWarning(EventIds.Jobs, "Tried to update changelogs of guild {Guild}, but it was null", guildId);
42+
continue;
43+
}
44+
sentChangelogs++;
45+
46+
// try to send new changelogs for each guild
47+
await PerformAsync(
48+
async ctx => await _updateGuildChangelogTask
49+
.Execute(ctx, new UpdateGuildChangelogTask.Args(guild.Id))
50+
, new JobExecutionOptions {
51+
PlaceInQueue = guild.Id
52+
, RelatedGuildId = guild.Id
53+
, Name = "send new changelogs"
54+
, Debug = guild.Id.ToString()
55+
});
56+
}
57+
_logger.LogInformation(EventIds.Jobs, "Finished sending changelogs. {Sent} changelogs were sent", sentChangelogs);
58+
}
59+
}

0 commit comments

Comments
 (0)