essa.jpeg

This commit is contained in:
2022-12-30 12:15:49 +01:00
parent 47abbbc0a7
commit 1f22aa4061
18 changed files with 420 additions and 37 deletions

View File

@@ -2,5 +2,8 @@
"api": {
"fallbackPort": 2020,
"memberCountGuildId": "447075692664979466"
},
"dsc": {
"slashCmdTestGuildId": "860916258282012692"
}
}

9
src/commands/ping.ts Normal file
View File

@@ -0,0 +1,9 @@
import { Command } from '../structures/Command';
export default new Command({
name: 'ping',
description: 'pongs back!',
run: async ({ interaction }) => {
interaction.followUp('pong');
},
});

9
src/commands/pomoc.ts Normal file
View File

@@ -0,0 +1,9 @@
import { Command } from '../structures/Command';
export default new Command({
name: 'pomoc',
description: 'pokazuje pomocne informacje',
run: async ({ interaction }) => {
interaction.followUp('tu będzie komenda z pomocami!');
},
});

View File

@@ -0,0 +1,6 @@
import { Event } from '../structures/Event';
import { members } from '..';
export default new Event('guildMemberAdd', () => {
members.incrementCurrent();
});

View File

@@ -0,0 +1,6 @@
import { Event } from '../structures/Event';
import { members } from '..';
export default new Event('guildMemberRemove', () => {
members.decrementCurrent();
});

View File

@@ -0,0 +1,18 @@
import { CommandInteractionOptionResolver } from 'discord.js';
import { client } from '..';
import { Event } from '../structures/Event';
import { BotInteraction } from '../typings/Command';
export default new Event('interactionCreate', async (interaction) => {
if (interaction.isCommand()) {
await interaction.deferReply();
const command = client.commands.get(interaction.commandName);
if (!command)
return interaction.followUp("This command doesn't exist. Dork.");
command.run({
args: interaction.options as CommandInteractionOptionResolver,
client,
interaction: interaction as BotInteraction,
});
}
});

23
src/events/ready.ts Normal file
View File

@@ -0,0 +1,23 @@
import { client, config, members } from '..';
import { Event } from '../structures/Event';
export default new Event('ready', () => {
console.log(`BOT: Now logged in as ${client.user?.tag}.`);
// memberCount reporting - for the API
// ---------------------------------------
// NOTE: for this to work, bot needs to be
// member of Gractwo Main Discord Server
members.setCurrent(
client.guilds.resolve(config.api.memberCountGuildId)?.memberCount || null
);
let intervalSeconds = 5;
setInterval(() => {
if (members.previous != members.current) {
console.log(
`API/BOT: Gractwo memberCount is ${`now ${members.current}` || 'unset'}`
);
}
members.setPrevious(members.current);
}, intervalSeconds * 1000);
});

View File

@@ -1,50 +1,26 @@
import DiscordJS from 'discord.js';
// import fs from 'fs';
import { BotClient } from './structures/Client';
import { MemberCount } from './structures/MemberCount';
import express from 'express';
import dotenv from 'dotenv';
import config from './cfg.json';
dotenv.config();
require('dotenv').config();
const client = new BotClient();
client.boot();
const client = new DiscordJS.Client({
intents: [
DiscordJS.GatewayIntentBits.Guilds,
DiscordJS.GatewayIntentBits.GuildMembers,
],
});
const app = express();
const port = process.env.PORT || config.api.fallbackPort;
let memberCount: number | null, previousCount: number | null;
const members = new MemberCount();
let port = process.env.PORT || config.api.fallbackPort;
app.get('/', (req, res) => {
res.sendStatus(200);
});
app.get('/members', (req, res) => {
res
.status(memberCount ? 200 : 500)
.send(memberCount ? memberCount.toString() : 'Server Error');
.status(members.current ? 200 : 500)
.send(members.current ? members.current.toString() : 'Server Error');
});
client.on('guildMemberAdd', () => {
if (memberCount) memberCount++;
});
client.on('guildMemberRemove', () => {
if (memberCount) memberCount--;
});
client.on('ready', () => {
console.log(`BOT: Now logged in as ${client.user?.tag}.`);
memberCount =
client.guilds.resolve(config.api.memberCountGuildId)?.memberCount || null;
setInterval(() => {
if (previousCount != memberCount) {
console.log(
`API/BOT: Gractwo memberCount is ${`now ${memberCount}` || 'unset'}.`
);
}
previousCount = memberCount;
}, 5 * 1000);
});
app.listen(port, () => {
console.log(`API: Now listening on :${port}.`);
});
client.login(process.env.TOKEN);
export { client, app, config, members };

84
src/structures/Client.ts Normal file
View File

@@ -0,0 +1,84 @@
import {
ApplicationCommandDataResolvable,
Client,
ClientEvents,
Collection,
GatewayIntentBits,
} from 'discord.js';
import { CommandType } from '../typings/Command';
import glob from 'glob';
import { promisify } from 'util';
import { RegisterCommandsOptions } from '../typings/Client';
import { Event } from './Event';
import config from '../cfg.json';
// makes file search lib a promise
const globPromise = promisify(glob);
class BotClient extends Client {
commands: Collection<string, CommandType> = new Collection();
constructor() {
super({
intents: 32767, // all intents!
});
}
boot() {
this.registerModules();
this.login(
// if prod, use main bot token
process.env.ENVIRONMENT == 'prod'
? process.env.TOKEN
: process.env.DEVTOKEN
);
}
async importFile(filePath: string) {
return (await import(filePath))?.default;
}
async registerCommands({ commands, guildId }: RegisterCommandsOptions) {
if (guildId) {
// register in guild
this.guilds.cache.get(guildId)?.commands.set(commands);
} else {
// register globally
this.application?.commands.set(commands);
}
}
async registerModules() {
const slashCommands: ApplicationCommandDataResolvable[] = [];
const commandFiles = await globPromise(
`${__dirname}/../commands/*{.ts,.,js}`
);
commandFiles.forEach(async (filePath) => {
const command: CommandType = await this.importFile(filePath);
if (!command.name) return;
this.commands.set(command.name, command);
slashCommands.push(command);
});
this.on('ready', () => {
this.registerCommands({
commands: slashCommands,
guildId: config.dsc.slashCmdTestGuildId,
});
// if prod, register global commands
if (process.env.ENVIRONMENT == 'prod') {
this.registerCommands({
commands: slashCommands,
});
}
});
const eventFiles = await globPromise(`${__dirname}/../events/*{.ts,.js}`);
eventFiles.forEach(async (filePath) => {
const event: Event<keyof ClientEvents> = await this.importFile(filePath);
this.on(event.event, event.run);
});
}
}
export { BotClient };

View File

@@ -0,0 +1,9 @@
import { CommandType } from '../typings/Command';
class Command {
constructor(commandOptions: CommandType) {
Object.assign(this, commandOptions);
}
}
export { Command };

10
src/structures/Event.ts Normal file
View File

@@ -0,0 +1,10 @@
import { ClientEvents } from 'discord.js';
class Event<Key extends keyof ClientEvents> {
constructor(
public event: Key,
public run: (...args: ClientEvents[Key]) => any
) {}
}
export { Event };

View File

@@ -0,0 +1,22 @@
class MemberCount {
current: number | null = null;
previous: number | null = null;
// "previous" is only used for reporting checks
// inside the ready.ts event
incrementCurrent() {
if (this.current) this.current++;
}
decrementCurrent() {
if (this.current) this.current--;
}
setCurrent(input: number | null) {
this.current = input;
}
setPrevious(input: number | null) {
this.previous = input;
}
}
export { MemberCount };

7
src/typings/Client.ts Normal file
View File

@@ -0,0 +1,7 @@
import { ApplicationCommandDataResolvable } from 'discord.js';
interface RegisterCommandsOptions {
guildId?: string;
commands: ApplicationCommandDataResolvable[];
}
export { RegisterCommandsOptions };

27
src/typings/Command.ts Normal file
View File

@@ -0,0 +1,27 @@
import {
ChatInputApplicationCommandData,
CommandInteraction,
CommandInteractionOptionResolver,
GuildMember,
PermissionResolvable,
} from 'discord.js';
import { BotClient } from '../structures/Client';
interface BotInteraction extends CommandInteraction {
member: GuildMember;
}
interface RunOptions {
client: BotClient;
interaction: BotInteraction;
args: CommandInteractionOptionResolver;
}
type RunFunction = (options: RunOptions) => any;
type CommandType = {
userPermissions?: PermissionResolvable[];
run: RunFunction;
} & ChatInputApplicationCommandData;
export { CommandType, BotInteraction };