-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathServerCommandModule.cs
More file actions
132 lines (117 loc) · 6.6 KB
/
Copy pathServerCommandModule.cs
File metadata and controls
132 lines (117 loc) · 6.6 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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using Discord.Interactions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using RustPlusBot.Features.Commands.Servers;
using RustPlusBot.Persistence.Workspace;
namespace RustPlusBot.Features.Commands.Modules;
/// <summary>Read-only live-data slash commands (/pop, /time, /wipe, /online, /offline, /team, /alive).</summary>
/// <param name="scopeFactory">Creates a short-lived DI scope per interaction.</param>
/// <param name="logger">The logger.</param>
public sealed partial class ServerCommandModule(
IServiceScopeFactory scopeFactory,
ILogger<ServerCommandModule> logger)
: InteractionModuleBase<SocketInteractionContext>
{
/// <summary>Shows the current player count.</summary>
/// <param name="server">The target server (only needed if more than one is registered).</param>
[SlashCommand("pop", "Show the current player count")]
public Task PopAsync(
[Summary("server", "Which server (only needed if more than one)")]
[Autocomplete(typeof(ServerAutocompleteHandler))]
string? server = null) => RunAsync("pop", server);
/// <summary>Shows the in-game time.</summary>
/// <param name="server">The target server (only needed if more than one is registered).</param>
[SlashCommand("time", "Show the in-game time")]
public Task TimeAsync(
[Summary("server", "Which server (only needed if more than one)")]
[Autocomplete(typeof(ServerAutocompleteHandler))]
string? server = null) => RunAsync("time", server);
/// <summary>Shows how long ago the server wiped.</summary>
/// <param name="server">The target server (only needed if more than one is registered).</param>
[SlashCommand("wipe", "Show how long ago the server wiped")]
public Task WipeAsync(
[Summary("server", "Which server (only needed if more than one)")]
[Autocomplete(typeof(ServerAutocompleteHandler))]
string? server = null) => RunAsync("wipe", server);
/// <summary>Lists online teammates.</summary>
/// <param name="server">The target server (only needed if more than one is registered).</param>
[SlashCommand("online", "List online teammates")]
public Task OnlineAsync(
[Summary("server", "Which server (only needed if more than one)")]
[Autocomplete(typeof(ServerAutocompleteHandler))]
string? server = null) => RunAsync("online", server);
/// <summary>Lists offline teammates.</summary>
/// <param name="server">The target server (only needed if more than one is registered).</param>
[SlashCommand("offline", "List offline teammates")]
public Task OfflineAsync(
[Summary("server", "Which server (only needed if more than one)")]
[Autocomplete(typeof(ServerAutocompleteHandler))]
string? server = null) => RunAsync("offline", server);
/// <summary>Lists all team members.</summary>
/// <param name="server">The target server (only needed if more than one is registered).</param>
[SlashCommand("team", "List all team members")]
public Task TeamAsync(
[Summary("server", "Which server (only needed if more than one)")]
[Autocomplete(typeof(ServerAutocompleteHandler))]
string? server = null) => RunAsync("team", server);
/// <summary>Shows how long each teammate has survived.</summary>
/// <param name="server">The target server (only needed if more than one is registered).</param>
[SlashCommand("alive", "Show how long each teammate has survived")]
public Task AliveAsync(
[Summary("server", "Which server (only needed if more than one)")]
[Autocomplete(typeof(ServerAutocompleteHandler))]
string? server = null) => RunAsync("alive", server);
/// <summary>Shows the small oil rig's status.</summary>
/// <param name="server">The target server (only needed if more than one is registered).</param>
[SlashCommand("small", "Show the small oil rig status")]
public Task SmallAsync(
[Summary("server", "Which server (only needed if more than one)")]
[Autocomplete(typeof(ServerAutocompleteHandler))]
string? server = null) => RunAsync("small", server);
/// <summary>Shows the large oil rig's status.</summary>
/// <param name="server">The target server (only needed if more than one is registered).</param>
[SlashCommand("large", "Show the large oil rig status")]
public Task LargeAsync(
[Summary("server", "Which server (only needed if more than one)")]
[Autocomplete(typeof(ServerAutocompleteHandler))]
string? server = null) => RunAsync("large", server);
private async Task RunAsync(string commandName, string? server)
{
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);
try
{
var scope = scopeFactory.CreateAsyncScope();
await using (scope.ConfigureAwait(false))
{
var workspace = scope.ServiceProvider.GetRequiredService<IWorkspaceStore>();
var resolver = scope.ServiceProvider.GetRequiredService<ServerResolver>();
var query = scope.ServiceProvider.GetRequiredService<ServerQueryService>();
var culture = await workspace.GetCultureAsync(Context.Guild.Id).ConfigureAwait(false);
var resolution = await resolver.ResolveAsync(Context.Guild.Id, server, culture, CancellationToken.None)
.ConfigureAwait(false);
if (resolution.ErrorMessage is { } error)
{
await FollowupAsync(error, ephemeral: true).ConfigureAwait(false);
return;
}
var reply = await query.RunAsync(commandName, Context.Guild.Id, resolution.ServerId!.Value, culture,
CancellationToken.None).ConfigureAwait(false);
await FollowupAsync(reply ?? "Something went wrong.", ephemeral: true).ConfigureAwait(false);
}
}
#pragma warning disable CA1031 // Broad catch: an interaction failure must not surface as a Discord "interaction failed".
catch (Exception ex)
#pragma warning restore CA1031
{
LogCommandFaulted(logger, ex, commandName);
await FollowupAsync("Something went wrong.", ephemeral: true).ConfigureAwait(false);
}
}
[LoggerMessage(Level = LogLevel.Error, Message = "Slash data command '{Command}' faulted.")]
private static partial void LogCommandFaulted(ILogger logger, Exception exception, string command);
}