diff --git a/docker-compose.yml b/docker-compose.yml index ebd54b3..5b5c24c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ services: bingusboingus: hostname: bingusboingus pull_policy: always - image: ghcr.io/blvckleg/bingusboingus:dev + image: ghcr.io/bingusboingus-developer-team/bingusboingus:dev volumes: - .env:/home/node/.env.prod environment: @@ -33,7 +33,7 @@ services: 'CMD', 'sh', '-c', - 'echo ''db.runCommand("ping").ok'' | mongosh localhost:27017 --quiet' + 'echo ''db.runCommand("ping").ok'' | mongosh localhost:27017 --quiet', ] interval: 10s timeout: 10s diff --git a/package-lock.json b/package-lock.json index c084dd2..d0efb5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "devDependencies": { "@eslint/js": "^9.2.0", "@types/express": "^4.17.17", + "@types/node-cron": "^3.0.11", "eslint": "^8.57.0", "globals": "^15.1.0", "prettier": "3.0.3", @@ -2423,6 +2424,12 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/node-cron": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/node-cron/-/node-cron-3.0.11.tgz", + "integrity": "sha512-0ikrnug3/IyneSHqCBeslAhlK2aBfYek1fGo4bP4QnZPmiqSGRK+Oy7ZMisLWkesffJvQ1cqAcBnJC+8+nxIAg==", + "dev": true + }, "node_modules/@types/qs": { "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", @@ -6694,7 +6701,7 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "engines": { - "node": ">=6" + "node": "*" } }, "node_modules/mimic-response": { diff --git a/package.json b/package.json index 091362a..f39aa42 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "devDependencies": { "@eslint/js": "^9.2.0", "@types/express": "^4.17.17", + "@types/node-cron": "^3.0.11", "eslint": "^8.57.0", "globals": "^15.1.0", "prettier": "3.0.3", diff --git a/src/modules/cron-tasks/cron-scheduler.ts b/src/modules/cron-tasks/cron-scheduler.ts deleted file mode 100644 index 6d0c351..0000000 --- a/src/modules/cron-tasks/cron-scheduler.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Client, TextChannel } from 'discord.js' -import { ITask } from './tasks/interfaces/task.interface' -import BirthdayShoutoutTask from './tasks/birthday-shoutout.task' -import * as cron from 'node-cron' -import { Inject } from '@nestjs/common' -import WakeUpTask from './tasks/wake-up.task' -import { BirthdayEntryService } from '../models/birthday/service/birthday-entry.service' - - -interface TaskEntry { - name: string - schedule: string - task: ITask -} - -class CronScheduler { - private static instance: CronScheduler - private client: Client - private tasks: TaskEntry[] - - constructor(client: Client, @Inject(BirthdayEntryService) private readonly birthdayService?: BirthdayEntryService) { - if (CronScheduler.instance) { - throw new Error(`ERROR: An instance has already been created.`) - } - this.client = client - this.tasks = [ - { - name: 'birthday-shoutout', - schedule: '0 10 * * *', - task: new BirthdayShoutoutTask( - this.client.channels.cache.find((channel) => channel.id === '447554141724737548') as TextChannel,birthdayService - ), - }, - { - name: 'first-of-the-month', - schedule: '0 12 1 * *', - task: new WakeUpTask( - this.client.channels.cache.find((channel) => channel.id === '447554141724737548') as TextChannel, - ), - }, - ] - - CronScheduler.instance = this - } - - static getInstance(): CronScheduler { - return CronScheduler.instance - } - - registerTasks(): void { - this.tasks.forEach((task) => { - if (!cron.validate(task.schedule)) { - throw new Error(`ERROR: Invalid cron schedule expression for task '${task.name}'`) - } - - cron.schedule(task.schedule, async () => { - await task.task.execute() - }).start() - }) - } -} - -export { CronScheduler } \ No newline at end of file diff --git a/src/modules/cron-tasks/cron.service.ts b/src/modules/cron-tasks/cron.service.ts new file mode 100644 index 0000000..02e3d54 --- /dev/null +++ b/src/modules/cron-tasks/cron.service.ts @@ -0,0 +1,72 @@ +import { Client, TextChannel } from 'discord.js'; +import BirthdayShoutoutTask from './tasks/birthday-shoutout.task'; +import { Inject, Injectable } from '@nestjs/common'; +import WakeUpTask from './tasks/wake-up.task'; +import * as cron from 'node-cron'; +import { BirthdayEntryService } from '../models/birthday/service/birthday-entry.service'; +import { TaskEntry } from './interfaces/task-entry.interface'; +import { DiscordService } from '../discord/discord.service'; + +@Injectable() +export class CronService { + private static instance: CronService; + private tasks: TaskEntry[]; + + constructor( + @Inject(BirthdayEntryService) + private readonly birthdayService: BirthdayEntryService, + @Inject(DiscordService) + private readonly discordService: DiscordService, + ) { + if (CronService.instance) { + throw new Error(`ERROR: An instance has already been created.`); + } + + CronService.instance = this; + } + + static getInstance(): CronService { + return CronService.instance; + } + + public init() { + this.tasks = [ + { + name: 'birthday-shoutout', + schedule: '0 10 * * *', + task: new BirthdayShoutoutTask( + this.discordService.client.channels.cache.find( + (channel) => channel.id === '447554141724737548', + ) as TextChannel, + this.birthdayService, + ), + }, + { + name: 'first-of-the-month', + schedule: '0 12 1 * *', + task: new WakeUpTask( + this.discordService.client.channels.cache.find( + (channel) => channel.id === '447554141724737548', + ) as TextChannel, + ), + }, + ]; + this.registerTasks(); + } + + registerTasks(): void { + this.tasks.forEach((task) => { + if (!cron.validate(task.schedule)) { + throw new Error( + `ERROR: Invalid cron schedule expression for task '${task.name}'`, + ); + } + + cron + .schedule(task.schedule, async () => { + await task.task.execute(); + }) + .start(); + }); + } +} diff --git a/src/modules/cron-tasks/interfaces/task-entry.interface.ts b/src/modules/cron-tasks/interfaces/task-entry.interface.ts new file mode 100644 index 0000000..ef05dee --- /dev/null +++ b/src/modules/cron-tasks/interfaces/task-entry.interface.ts @@ -0,0 +1,7 @@ +import { ITask } from '../tasks/interfaces/task.interface'; + +export interface TaskEntry { + name: string; + schedule: string; + task: ITask; +} diff --git a/src/modules/cron-tasks/task.module.ts b/src/modules/cron-tasks/task.module.ts index 714df29..98edce4 100644 --- a/src/modules/cron-tasks/task.module.ts +++ b/src/modules/cron-tasks/task.module.ts @@ -1,12 +1,11 @@ -import { Module } from "@nestjs/common"; -import { BirthdayEntryModule } from "../models/birthday/module/birthday-entry.module"; - +import { Module } from '@nestjs/common'; +import { BirthdayEntryModule } from '../models/birthday/module/birthday-entry.module'; +import { CronService } from './cron.service'; +import { DiscordModule } from '../discord/discord.module'; @Module({ - imports: [ - BirthdayEntryModule, - ], - providers: [], - exports: [], + imports: [DiscordModule, BirthdayEntryModule], + providers: [CronService], + exports: [CronService], }) export class TaskModule {} diff --git a/src/modules/discord/discord.service.ts b/src/modules/discord/discord.service.ts index d21e2a9..d1ad3bd 100644 --- a/src/modules/discord/discord.service.ts +++ b/src/modules/discord/discord.service.ts @@ -1,15 +1,12 @@ import { Injectable } from '@nestjs/common'; import { Client, GatewayIntentBits } from 'discord.js'; import { AppConfigService } from '../../config/config.service'; -import { CronScheduler } from '../cron-tasks/cron-scheduler'; -import { BirthdayEntryService } from '../models/birthday/service/birthday-entry.service'; @Injectable() export class DiscordService { public readonly client: Client; - public cronScheduler: CronScheduler; - constructor(configService: AppConfigService, private readonly birthdayService: BirthdayEntryService) { + constructor(configService: AppConfigService) { this.client = new Client({ intents: [ GatewayIntentBits.Guilds, @@ -17,11 +14,6 @@ export class DiscordService { GatewayIntentBits.MessageContent, ], }); - this.client.login(configService.botToken); - this.client.on('ready', () => { - this.cronScheduler = new CronScheduler(this.client, birthdayService); - this.cronScheduler.registerTasks(); - }); } } diff --git a/src/modules/event/event.module.ts b/src/modules/event/event.module.ts index 4f191b7..e8817b3 100644 --- a/src/modules/event/event.module.ts +++ b/src/modules/event/event.module.ts @@ -6,9 +6,10 @@ import { MessageEvent } from './services/messageEvent'; import { DiscordModule } from '../discord/discord.module'; import { CommandModule } from '../command/command.module'; import { PollModule } from '../models/poll/module/poll.module'; +import { TaskModule } from '../cron-tasks/task.module'; @Module({ - imports: [DiscordModule, CommandModule, PollModule], + imports: [DiscordModule, TaskModule, CommandModule, PollModule], providers: [EventService, ClientReady, Interaction, MessageEvent], exports: [EventService], }) diff --git a/src/modules/event/services/clientReady.ts b/src/modules/event/services/clientReady.ts index 7ffcc1c..f79a88a 100644 --- a/src/modules/event/services/clientReady.ts +++ b/src/modules/event/services/clientReady.ts @@ -1,14 +1,21 @@ import { Injectable } from '@nestjs/common'; import { ClientEvents, Events } from 'discord.js'; import { AEvent } from '../event.abstract'; +import { CronService } from '../../cron-tasks/cron.service'; @Injectable() export class ClientReady extends AEvent { + constructor(private readonly cronService: CronService) { + super(); + } + event: keyof ClientEvents = Events.ClientReady; once: boolean = true; async execute(args: ClientEvents[Events.ClientReady]) { console.log('Successfully connected to Discord'); console.log(`logged in as ${args[0].user.username}`); + + this.cronService.init(); } }