Quota: Refactor how Quotas are being handled
also renamed limits to quota I believe this new approach would allow me and bot hosters to add, implement or change the quota behavior more easily. Reimplemented the currently existing "Message count" limit to use the new IQuota, refactoring a code *a little*.
This commit is contained in:
parent
46bb5c867d
commit
339ef06ff9
5 changed files with 214 additions and 107 deletions
|
@ -8,7 +8,7 @@ import toOpenAIMessages from "./toOpenAIMessages";
|
|||
import FunctionManager from "./funcitonManager";
|
||||
|
||||
type NonNullableInObject<T, V> = { [k in keyof T]: k extends V ? NonNullable<T[k]> : T[k] };
|
||||
type apiRequest = DiscordApi.Message | DiscordApi.RepliableInteraction;
|
||||
export type apiRequest = DiscordApi.Message | DiscordApi.RepliableInteraction;
|
||||
export type RequestMessage = apiRequest & NonNullableInObject<apiRequest, "channel" | "channelId">;
|
||||
|
||||
class ChannelsRunningValue extends Array<RequestMessage> {
|
||||
|
@ -60,69 +60,6 @@ export function getAuthor(request: apiRequest) {
|
|||
return request.user;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets user remaining limit (or lack of it)
|
||||
* @param user the user to check
|
||||
* @param requestTimestamp the timestamp of the user request
|
||||
* @returns object containing the limit and remaining usage or `false` if there is no limit
|
||||
*/
|
||||
export async function getUserLimit(user: string | { id: string }, requestTimestamp: Date) {
|
||||
const userId: string = typeof user === "string" ? user : user.id;
|
||||
|
||||
const userLimits = await database.limits.findUnique({
|
||||
where: { user: BigInt(userId) }
|
||||
});
|
||||
|
||||
if (userLimits?.vip) return false;
|
||||
|
||||
const usedLimit = (await database.usage.count({
|
||||
select: { _all: true },
|
||||
where: {
|
||||
user: BigInt(userId),
|
||||
timestamp: {
|
||||
gte: new Date(requestTimestamp.getTime() - 1000 * 60 * 60 * 24 /* 24 hours */)
|
||||
}
|
||||
},
|
||||
}))._all;
|
||||
|
||||
if (!userLimits || !userLimits.limit) return {limit: config.userLimits.requests, remaining: config.userLimits.requests - usedLimit};
|
||||
|
||||
return {limit: userLimits.limit, remaining: userLimits.limit - usedLimit};
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the timestamp of nth use inside time limit
|
||||
* @param user the user or id to check
|
||||
* @param requestTimestamp the timestamp of the request (message/interaction createdAt)
|
||||
* @param nth which timestamp in time limit to get (orderedd from oldest to newest)
|
||||
* @returns `false` if user is vip
|
||||
* @returns `null` if there is no request
|
||||
* @returns `Date` timestamp of the nth request
|
||||
*/
|
||||
export async function getNthUseInLimitTimestamp(user: string | { id: string }, requestTimestamp: Date, nth = 1) {
|
||||
const userId: string = typeof user === "string" ? user : user.id;
|
||||
|
||||
const userLimits = await database.limits.findUnique({
|
||||
where: { user: BigInt(userId)}
|
||||
});
|
||||
|
||||
if (userLimits?.vip) return false;
|
||||
|
||||
const nthUseInLimit = await database.usage.findFirst({
|
||||
where: {
|
||||
user: BigInt(userId),
|
||||
timestamp: {
|
||||
gte: new Date(requestTimestamp.getTime() - 1000 * 60 * 60 * 24 /* 24 hours */)
|
||||
}
|
||||
},
|
||||
orderBy: { timestamp: "asc" },
|
||||
skip: nth - 1,
|
||||
});
|
||||
|
||||
if (!nthUseInLimit) return null;
|
||||
return nthUseInLimit.timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replies to a request
|
||||
* @param request the request to reply to
|
||||
|
@ -194,9 +131,9 @@ export async function queueRequest(request: apiRequest) {
|
|||
return;
|
||||
}
|
||||
|
||||
const userLimit = await getUserLimit(getAuthor(request), request.createdAt);
|
||||
const userLimit = await config.quota.checkUser(getAuthor(request), request);
|
||||
|
||||
if (userLimit !== false && userLimit.remaining <= 0) {
|
||||
if (userLimit.used >= userLimit.quota) {
|
||||
if (request instanceof DiscordApi.Message) {
|
||||
request.react("🛑").catch(() => { /* NOTE: We send an informaton about limit reached in DM */ });
|
||||
if (!request.author.dmChannel) await request.author.createDM();
|
||||
|
@ -204,14 +141,13 @@ export async function queueRequest(request: apiRequest) {
|
|||
embeds: [{
|
||||
color: 0xff0000,
|
||||
description:
|
||||
"You've used up your message limit for today,\n" +
|
||||
`${userLimit.limit} requests in last 24 hours`,
|
||||
"You've used up your quota,\n" + userLimit.toString(),
|
||||
}]
|
||||
}).catch(() => {/* FIXME: What should the bot do in this case to inform of limit reached?*/});
|
||||
}
|
||||
else if (request.isRepliable()) {
|
||||
request.reply({
|
||||
content: `You've used up your message limit for today, ${userLimit.limit} requests in last 24 hours`,
|
||||
content: "You've used up your quota\n" + userLimit.toString(),
|
||||
ephemeral: true,
|
||||
}).catch(() => { /* Impossible to get there unless connection lost*/ });
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue