feat: check for locales

This commit is contained in:
MARCROCK22 2024-06-28 05:58:30 +00:00
parent f05ba46b3a
commit 0be7c73d4a
2 changed files with 82 additions and 33 deletions

View File

@ -284,13 +284,29 @@ export class BaseClient {
throw new Error('Function not implemented');
}
private shouldUploadCommands(cachePath: string) {
return this.commands!.shouldUpload(cachePath).then(async should => {
if (should) await promises.writeFile(cachePath, JSON.stringify(this.commands!.values.map(x => x.toJSON())));
private shouldUploadCommands(cachePath: string, guildId?: string) {
return this.commands!.shouldUpload(cachePath, guildId).then(should => {
this.logger.debug(
should
? `[${guildId ?? 'global'}] Change(s) detected, uploading commands`
: `[${guildId ?? 'global'}] commands seems to be up to date`,
);
return should;
});
}
private syncCachePath(cachePath: string) {
this.logger.debug('Syncing commands cache');
return promises.writeFile(
cachePath,
JSON.stringify(
this.commands!.values.filter(cmd => !('ignore' in cmd) || cmd.ignore !== IgnoreCommand.Slash).map(x =>
x.toJSON(),
),
),
);
}
async uploadCommands({ applicationId, cachePath }: { applicationId?: string; cachePath?: string } = {}) {
applicationId ??= await this.getRC().then(x => x.applicationId ?? this.applicationId);
BaseClient.assertString(applicationId, 'applicationId is not a string');
@ -298,18 +314,12 @@ export class BaseClient {
const commands = this.commands!.values;
const filter = filterSplit(commands, command => !command.guildId);
if (!cachePath || (cachePath && (await this.shouldUploadCommands(cachePath))))
await this.proxy
.applications(applicationId)
.commands.put({
body: filter.expect
.filter(cmd => !('ignore' in cmd) || cmd.ignore !== IgnoreCommand.Slash)
.map(x => x.toJSON()),
})
.catch(async e => {
if (cachePath) await promises.unlink(cachePath);
throw e;
});
if (!cachePath || (await this.shouldUploadCommands(cachePath)))
await this.proxy.applications(applicationId).commands.put({
body: filter.expect
.filter(cmd => !('ignore' in cmd) || cmd.ignore !== IgnoreCommand.Slash)
.map(x => x.toJSON()),
});
const guilds = new Set<string>();
@ -319,16 +329,22 @@ export class BaseClient {
}
}
for (const guild of guilds) {
await this.proxy
.applications(applicationId)
.guilds(guild)
.commands.put({
body: filter.never
.filter(cmd => cmd.guildId?.includes(guild) && (!('ignore' in cmd) || cmd.ignore !== IgnoreCommand.Slash))
.map(x => x.toJSON()),
});
for (const guildId of guilds) {
if (!cachePath || (await this.shouldUploadCommands(cachePath, guildId))) {
await this.proxy
.applications(applicationId)
.guilds(guildId)
.commands.put({
body: filter.never
.filter(
cmd => cmd.guildId?.includes(guildId) && (!('ignore' in cmd) || cmd.ignore !== IgnoreCommand.Slash),
)
.map(x => x.toJSON()),
});
}
}
if (cachePath) await this.syncCachePath(cachePath);
}
async loadCommands(dir?: string) {
@ -363,7 +379,7 @@ export class BaseClient {
T extends InternalRuntimeConfigHTTP | InternalRuntimeConfig = InternalRuntimeConfigHTTP | InternalRuntimeConfig,
>() {
const seyfertConfig = (BaseClient._seyfertConfig ||
(await this.options.getRC?.()) ||
(await this.options?.getRC?.()) ||
(await Promise.any(
['.js', '.mjs', '.cjs', '.ts', '.mts', '.cts'].map(ext =>
magicImport(join(process.cwd(), `seyfert.config${ext}`)).then(x => x.default ?? x),

View File

@ -8,6 +8,7 @@ import {
type APIApplicationCommandSubcommandOption,
type APIApplicationCommandSubcommandGroupOption,
type APIApplicationCommandChannelOption,
type LocalizationMap,
} from 'discord-api-types/v10';
import { basename, dirname } from 'node:path';
import type { Logger, MakeRequired, NulleableCoalising, OmitInsert } from '../common';
@ -48,6 +49,24 @@ export class CommandHandler extends BaseHandler {
}
}
protected shouldUploadLocales(locales?: LocalizationMap | null, cachedLocales?: LocalizationMap | null) {
if (!locales && !cachedLocales) return false;
if (!locales && cachedLocales) return true;
if (locales && !cachedLocales) return true;
if (locales && cachedLocales) {
const localesEntries = Object.entries(locales);
const cachedLocalesEntries = Object.entries(cachedLocales);
if (localesEntries.length !== cachedLocalesEntries.length) return true;
for (const [key, value] of localesEntries) {
const cached = cachedLocalesEntries.find(x => x[0] === key);
if (!cached) return true;
if (value !== cached[1]) return true;
}
}
return false;
}
protected shouldUploadOption(option: APIApplicationCommandOption, cached: APIApplicationCommandOption) {
if (option.description !== cached.description) return true;
if (option.type !== cached.type) return true;
@ -55,6 +74,9 @@ export class CommandHandler extends BaseHandler {
if (option.name !== cached.name) return true;
//TODO: locales
if (this.shouldUploadLocales(option.name_localizations, cached.name_localizations)) return true;
if (this.shouldUploadLocales(option.description_localizations, cached.description_localizations)) return true;
switch (option.type) {
case ApplicationCommandOptionType.String:
return (
@ -108,24 +130,34 @@ export class CommandHandler extends BaseHandler {
return false;
}
async shouldUpload(file: string) {
async shouldUpload(file: string, guildId?: string) {
const values = this.values.filter(x => {
if (!guildId) return !x.guildId;
return x.guildId?.includes(guildId);
});
if (
!(await promises.access(file).then(
() => true,
() => false,
))
) {
await promises.writeFile(file, JSON.stringify(this.values.map(x => x.toJSON())));
await promises.writeFile(file, JSON.stringify(values.map(x => x.toJSON())));
return true;
}
const cachedCommands: (ReturnType<Command['toJSON']> | ReturnType<ContextMenuCommand['toJSON']>)[] = JSON.parse(
(await promises.readFile(file)).toString(),
);
const cachedCommands = (
JSON.parse((await promises.readFile(file)).toString()) as (
| ReturnType<Command['toJSON']>
| ReturnType<ContextMenuCommand['toJSON']>
)[]
).filter(x => {
if (!guildId) return !x.guild_id;
return x.guild_id?.includes(guildId);
});
if (cachedCommands.length !== this.values.length) return true;
if (cachedCommands.length !== values.length) return true;
for (const command of this.values.map(x => x.toJSON())) {
for (const command of values.map(x => x.toJSON())) {
const cached = cachedCommands.find(x => {
if (x.name !== command.name) return false;
if (command.guild_id) return command.guild_id.every(id => x.guild_id?.includes(id));
@ -140,7 +172,8 @@ export class CommandHandler extends BaseHandler {
if (!!('options' in cached) !== !!('options' in command)) return true;
if (!!cached.contexts !== !!command.contexts) return true;
if (!!cached.integration_types !== !!command.integration_types) return true;
//TODO: locales
if (this.shouldUploadLocales(command.name_localizations, cached.name_localizations)) return true;
if (this.shouldUploadLocales(command.description_localizations, cached.description_localizations)) return true;
if ('contexts' in command && 'contexts' in cached) {
if (command.contexts.length !== cached.contexts.length) return true;