Skip to content

Commit 3833367

Browse files
feat: queue view and cancel commands
1 parent 85deb3b commit 3833367

File tree

5 files changed

+172
-1
lines changed

5 files changed

+172
-1
lines changed

src/framework/typescript/queues/QueueManager.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ class QueueManager extends HasApplication {
3232
return this.scheduledQueues;
3333
}
3434

35+
public getJob(id: number) {
36+
return this.scheduledQueues.get(id);
37+
}
38+
3539
public create<T extends StorableData>(
3640
queue: string | QueueClass,
3741
options: QueueOptions<T>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { TakesArgument } from "@framework/arguments/ArgumentTypes";
2+
import IntegerArgument from "@framework/arguments/IntegerArgument";
3+
import { ErrorType } from "@framework/arguments/InvalidArgumentError";
4+
import { Command } from "@framework/commands/Command";
5+
import type Context from "@framework/commands/Context";
6+
import { Inject } from "@framework/container/Inject";
7+
import QueueService from "@main/services/QueueService";
8+
import { PermissionFlagsBits } from "discord.js";
9+
10+
type QueueCancelCommandArgs = {
11+
id: number;
12+
};
13+
14+
@TakesArgument<QueueCancelCommandArgs>({
15+
names: ["id"],
16+
types: [IntegerArgument],
17+
optional: false,
18+
errorMessages: [
19+
{
20+
[ErrorType.Required]: "You must provide a Queued Job ID!",
21+
[ErrorType.InvalidType]: "The provided ID is not a valid integer!"
22+
}
23+
],
24+
interactionName: "id"
25+
})
26+
class QueueCancelCommand extends Command {
27+
public override readonly name = "queue::cancel";
28+
public override readonly description: string = "Cancels a queued job.";
29+
public override readonly defer = true;
30+
public override readonly permissions = [PermissionFlagsBits.ManageGuild];
31+
public override readonly usage = ["<id: Int>"];
32+
public override readonly aliases = ["queue::remove", "queue::delete"];
33+
34+
@Inject()
35+
private readonly queueService!: QueueService;
36+
37+
public override async execute(context: Context, args: QueueCancelCommandArgs): Promise<void> {
38+
const job = this.queueService.getJob(args.id);
39+
40+
if (!job) {
41+
return void (await context.error("No queued job found with that ID."));
42+
}
43+
44+
if (job.isExecuting) {
45+
return void (await context.error(
46+
"You cannot cancel a job that is currently executing."
47+
));
48+
}
49+
50+
await job.cancel();
51+
52+
await context.success(`Successfully cancelled the job with ID ${job.id}.`);
53+
}
54+
}
55+
56+
export default QueueCancelCommand;

src/main/typescript/commands/automation/QueueCommand.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@ class QueueCommand extends Command {
99
public override readonly defer = true;
1010
public override readonly usage = ["<subcommand: String> [...args: Any[]]"];
1111
public override readonly systemPermissions = [];
12-
public override readonly subcommands = ["list", "cancel", "show", "add"];
12+
public override readonly subcommands = [
13+
"list",
14+
"cancel",
15+
"show",
16+
"view",
17+
"add",
18+
"remove",
19+
"delete"
20+
];
1321
public override readonly isolatedSubcommands = true;
1422
public override readonly aliases = ["queues", "q"];
1523
public override readonly permissions = [PermissionFlagsBits.ManageGuild];
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { TakesArgument } from "@framework/arguments/ArgumentTypes";
2+
import IntegerArgument from "@framework/arguments/IntegerArgument";
3+
import { ErrorType } from "@framework/arguments/InvalidArgumentError";
4+
import { Command } from "@framework/commands/Command";
5+
import type Context from "@framework/commands/Context";
6+
import { Inject } from "@framework/container/Inject";
7+
import { shortUserInfo } from "@framework/utils/embeds";
8+
import { Colors } from "@main/constants/Colors";
9+
import CommandExecutionQueue from "@main/queues/CommandExecutionQueue";
10+
import QueueService from "@main/services/QueueService";
11+
import { PermissionFlagsBits, inlineCode, italic, time } from "discord.js";
12+
13+
type QueueViewCommandArgs = {
14+
id: number;
15+
};
16+
17+
@TakesArgument<QueueViewCommandArgs>({
18+
names: ["id"],
19+
types: [IntegerArgument],
20+
optional: false,
21+
errorMessages: [
22+
{
23+
[ErrorType.Required]: "You must provide a Queued Job ID!",
24+
[ErrorType.InvalidType]: "The provided ID is not a valid integer!"
25+
}
26+
],
27+
interactionName: "id"
28+
})
29+
class QueueViewCommand extends Command {
30+
public override readonly name = "queue::view";
31+
public override readonly description: string = "Shows information about a queued job.";
32+
public override readonly defer = true;
33+
public override readonly permissions = [PermissionFlagsBits.ManageGuild];
34+
public override readonly usage = ["<id: Int>"];
35+
public override readonly aliases = ["queue::show"];
36+
37+
@Inject()
38+
private readonly queueService!: QueueService;
39+
40+
public override async execute(context: Context, args: QueueViewCommandArgs): Promise<void> {
41+
const job = this.queueService.getJob(args.id);
42+
43+
if (!job) {
44+
return void (await context.error("No queued job found with that ID."));
45+
}
46+
47+
const fields = [
48+
{
49+
name: "Type",
50+
value: inlineCode(
51+
(job.constructor as unknown as { uniqueName: string }).uniqueName
52+
),
53+
inline: false
54+
},
55+
{
56+
name: "Created By",
57+
value: job.userId
58+
? job.userId === "0"
59+
? "[Unknown]"
60+
: shortUserInfo(this.application.client, job.userId)
61+
: italic("Unknown"),
62+
inline: false
63+
},
64+
{
65+
name: "Creation Time",
66+
value: job.createdAt
67+
? `${time(job.createdAt, "F")} (${time(job.createdAt, "R")})`
68+
: "`[Not yet created]`",
69+
inline: true
70+
},
71+
{
72+
name: "Execution Time",
73+
value: `${time(job.runsAt, "F")} (${time(job.runsAt, "R")})`,
74+
inline: true
75+
}
76+
];
77+
78+
if (job instanceof CommandExecutionQueue) {
79+
fields.push({
80+
name: "Command To Execute",
81+
value: inlineCode(job.data.commandString),
82+
inline: false
83+
});
84+
}
85+
86+
await context.reply({
87+
embeds: [
88+
{
89+
title: `Job #${job.id}`,
90+
color: Colors.Primary,
91+
fields,
92+
timestamp: new Date().toISOString()
93+
}
94+
]
95+
});
96+
}
97+
}
98+
99+
export default QueueViewCommand;

src/main/typescript/services/QueueService.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ class QueueService extends Service implements HasEventListeners {
2424
return this.queueManager.getJobs();
2525
}
2626

27+
public getJob(id: number) {
28+
return this.queueManager.getJob(id);
29+
}
30+
2731
public async sync(): Promise<void> {
2832
const queues = await this.application.prisma.queue.findMany({
2933
where: {

0 commit comments

Comments
 (0)