-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDiagnosticsModule.cs
More file actions
76 lines (67 loc) · 3.48 KB
/
Copy pathDiagnosticsModule.cs
File metadata and controls
76 lines (67 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
using System.Diagnostics;
using System.Globalization;
using Discord;
using Discord.Interactions;
using Microsoft.Extensions.DependencyInjection;
using RustPlusBot.Features.Commands.Formatting;
using RustPlusBot.Features.Commands.Hosting;
using RustPlusBot.Persistence.Connections;
using RustPlusBot.Persistence.Servers;
namespace RustPlusBot.Features.Commands.Modules;
/// <summary>Read-only diagnostics: /ping and /status.</summary>
/// <param name="scopeFactory">Creates a short-lived DI scope per interaction.</param>
public sealed class DiagnosticsModule(IServiceScopeFactory scopeFactory)
: InteractionModuleBase<SocketInteractionContext>
{
/// <summary>Reports Discord gateway latency and the REST ack round-trip.</summary>
[SlashCommand("ping", "Show the bot's Discord latency")]
public async Task PingAsync()
{
var stopwatch = Stopwatch.StartNew();
await DeferAsync(ephemeral: true).ConfigureAwait(false);
stopwatch.Stop();
var text = string.Create(CultureInfo.InvariantCulture,
$"Pong! Gateway: {Context.Client.Latency} ms · Response: {stopwatch.ElapsedMilliseconds} ms");
await FollowupAsync(text, ephemeral: true).ConfigureAwait(false);
}
/// <summary>Shows uptime, latency, per-server connection status, and counts.</summary>
[SlashCommand("status", "Show bot health and connection status")]
public async Task StatusAsync()
{
if (Context.Guild is null)
{
await RespondAsync("This command must be used in a server.", ephemeral: true).ConfigureAwait(false);
return;
}
await DeferAsync(ephemeral: true).ConfigureAwait(false);
var scope = scopeFactory.CreateAsyncScope();
await using (scope.ConfigureAwait(false))
{
var uptime = scope.ServiceProvider.GetRequiredService<BotUptime>();
var servers = scope.ServiceProvider.GetRequiredService<IServerService>();
var connections = scope.ServiceProvider.GetRequiredService<IConnectionStore>();
var known = await servers.ListAsync(Context.Guild.Id).ConfigureAwait(false);
var states = (await connections.GetStatesForGuildAsync(Context.Guild.Id).ConfigureAwait(false))
.ToDictionary(state => state.RustServerId);
var embed = new EmbedBuilder()
.WithTitle("Bot status")
.AddField("Uptime", DurationFormat.Compact(uptime.Elapsed), inline: true)
.AddField("Gateway latency",
string.Create(CultureInfo.InvariantCulture, $"{Context.Client.Latency} ms"), inline: true)
.AddField("Guilds",
Context.Client.Guilds.Count.ToString(CultureInfo.InvariantCulture), inline: true)
.AddField("Servers (this guild)",
known.Count.ToString(CultureInfo.InvariantCulture), inline: true);
// Cap server fields so the embed stays under Discord's 25-field limit (4 header fields above).
foreach (var server in known.Take(20))
{
var line = states.TryGetValue(server.Id, out var state)
? string.Create(CultureInfo.InvariantCulture,
$"{state.Status} · {state.PlayerCount?.ToString(CultureInfo.InvariantCulture) ?? "?"} players")
: "unknown";
embed.AddField(server.Name, line);
}
await FollowupAsync(ephemeral: true, embed: embed.Build()).ConfigureAwait(false);
}
}
}