diff --git a/package-lock.json b/package-lock.json index 6def213..e28b0d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "@types/ping": "^0.4.4", + "cron": "^4.3.3", "discord.js": "^14.24.1", "dotenv": "^17.2.2", "ping": "^1.0.0" @@ -178,6 +179,12 @@ "npm": ">=7.0.0" } }, + "node_modules/@types/luxon": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.7.1.tgz", + "integrity": "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "24.9.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", @@ -212,6 +219,19 @@ "npm": ">=7.0.0" } }, + "node_modules/cron": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/cron/-/cron-4.3.3.tgz", + "integrity": "sha512-B/CJj5yL3sjtlun6RtYHvoSB26EmQ2NUmhq9ZiJSyKIM4K/fqfh9aelDFlIayD2YMeFZqWLi9hHV+c+pq2Djkw==", + "license": "MIT", + "dependencies": { + "@types/luxon": "~3.7.0", + "luxon": "~3.7.0" + }, + "engines": { + "node": ">=18.x" + } + }, "node_modules/discord-api-types": { "version": "0.38.31", "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.31.tgz", @@ -278,6 +298,15 @@ "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", "license": "MIT" }, + "node_modules/luxon": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", + "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/magic-bytes.js": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.12.1.tgz", diff --git a/package.json b/package.json index 721ec13..83c14fb 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ }, "dependencies": { "@types/ping": "^0.4.4", + "cron": "^4.3.3", "discord.js": "^14.24.1", "dotenv": "^17.2.2", "ping": "^1.0.0" diff --git a/src/commands/utility/ping.ts b/src/commands/utility/ping.ts index f7bb0d2..48d9b60 100644 --- a/src/commands/utility/ping.ts +++ b/src/commands/utility/ping.ts @@ -14,6 +14,6 @@ export default { InteractionContextType.PrivateChannel ), async execute(interaction : ChatInputCommandInteraction) { - await interaction.reply('Pong !'); + await interaction.reply(`🏓 Latency is ${Date.now() - interaction.createdTimestamp}ms. API Latency : ${interaction.client.ws.ping}ms`); } } \ No newline at end of file diff --git a/src/commands/utility/statut.ts b/src/commands/utility/statut.ts index 3204117..255861c 100644 --- a/src/commands/utility/statut.ts +++ b/src/commands/utility/statut.ts @@ -1,5 +1,6 @@ import { ApplicationIntegrationType, ChatInputCommandInteraction, CommandInteraction, EmbedBuilder, InteractionContextType, SlashCommandBuilder } from "discord.js"; import ping from "ping"; +import statusService from "../../services/status.service"; export default { data: new SlashCommandBuilder() @@ -16,81 +17,6 @@ export default { ), async execute(interaction : ChatInputCommandInteraction) { await interaction.deferReply(); - - const hosts : {host: string, name: string, alive: boolean, type: 'ping' | 'website'}[] = [ - { - 'host': 'https://protojx.com', - 'name': 'Protojx Website 🌐', - alive: false, - type: 'website' - }, - { - 'host': 'https://manager.protojx.com', - 'name': 'Espace Client 💻', - alive: false, - type: 'website' - }, - { - host: '5.178.99.4', - name: 'RYZEN 01 🖥️', - alive: false, - type: 'ping' - }, - { - host: '5.167.99.6', - name: 'RYZEN 02 🖥️', - alive: false, - type: 'ping' - }, - { - host: '5.178.99.5', - name: 'RYZEN 03 🖥️', - alive: false, - type: 'ping' - }, - { - host: '5.178.99.177', - name: 'XEON 01 (2697A V4) 🖥️', - alive: false, - type: 'ping' - }, - { - host: '5.178.99.248', - name: 'XEON 02 (2687W V4) 🖥️', - alive: false, - type: 'ping' - }, - { - host: '5.178.99.53', - name: 'RYZEN-GAME 01 👾', - alive: false, - type: 'ping' - }, - { - host: '5.178.99.63', - name: 'XEON-GAME 01 👾', - alive: false, - type: 'ping' - } - ] - - async function fetchAlive(host: {host: string, name: string, alive: boolean, type: 'ping' | 'website'}) { - if(host.type === 'ping'){ - let res = await ping.promise.probe(host.host, {timeout: 5}); - host.alive = res.alive; - }else if(host.type === 'website'){ - try { - const response = await fetch(host.host, { method: 'HEAD', signal: AbortSignal.timeout(3000) }); - host.alive = response.ok; - } catch (error) { - host.alive = false; - } - } - return host; - } - - const fetchPromises = hosts.map(host => fetchAlive(host)); - const hosts_ = await Promise.all(fetchPromises); const embed = new EmbedBuilder(); embed.setTitle('Status of protojx servers'); @@ -98,7 +24,7 @@ export default { embed.setTimestamp(new Date()); embed.setThumbnail(interaction.client.user.avatarURL()) - for(let host of hosts_){ + for(let host of statusService.hosts){ embed.addFields({name: host.name, value: host.alive ? ' Online' : ' Offline', inline: false}); } diff --git a/src/services/status.service.ts b/src/services/status.service.ts new file mode 100644 index 0000000..1953998 --- /dev/null +++ b/src/services/status.service.ts @@ -0,0 +1,112 @@ +import ping from "ping"; +import * as cron from 'cron'; + +export class StatusService { + + public hosts : Host[] = [ + { + 'host': 'https://protojx.com', + 'name': 'Protojx Website 🌐', + alive: false, + type: 'website' + }, + { + 'host': 'https://manager.protojx.com', + 'name': 'Espace Client 💻', + alive: false, + type: 'website' + }, + { + host: '5.178.99.4', + name: 'RYZEN 01 🖥️', + alive: false, + type: 'ping' + }, + { + host: '5.167.99.6', + name: 'RYZEN 02 🖥️', + alive: false, + type: 'ping' + }, + { + host: '5.178.99.5', + name: 'RYZEN 03 🖥️', + alive: false, + type: 'ping' + }, + { + host: '5.178.99.177', + name: 'XEON 01 (2697A V4) 🖥️', + alive: false, + type: 'ping' + }, + { + host: '5.178.99.248', + name: 'XEON 02 (2687W V4) 🖥️', + alive: false, + type: 'ping' + }, + { + host: '5.178.99.53', + name: 'RYZEN-GAME 01 👾', + alive: false, + type: 'ping' + }, + { + host: '5.178.99.63', + name: 'XEON-GAME 01 👾', + alive: false, + type: 'ping' + } + ] + + constructor() { + const cronJob = new cron.CronJob('*/2 * * * *', async () => { + try { + await this.fetch(); + console.log('Status check completed at:', new Date().toISOString()); + } catch (error) { + console.error('Error during status check:', error); + } + }); + cronJob.start(); + console.log('Status monitoring started - checking every 2 minutes'); + } + + async fetch(max = 1): Promise { + + const hosts = this.hosts.filter((value, index) => index < max * 10 && index >= (max - 1) * 10); + async function fetchAlive(host: Host) { + if(host.type === 'ping'){ + let res = await ping.promise.probe(host.host, {timeout: 5}); + host.alive = res.alive; + }else if(host.type === 'website'){ + try { + const response = await fetch(host.host, { method: 'HEAD', signal: AbortSignal.timeout(3000) }); + host.alive = response.ok; + } catch (error) { + host.alive = false; + } + } + return host; + } + + const fetchPromises = hosts.map(host => fetchAlive(host)); + const updatedHosts = await Promise.all(fetchPromises); + + updatedHosts.forEach((updatedHost, index) => { + const originalIndex = (max - 1) * 10 + index; + if (originalIndex < this.hosts.length) { + this.hosts[originalIndex] = updatedHost; + } + }); + + if(this.hosts.length > max * 10) { + await this.fetch(max + 1); + } + + return this.hosts; + } +} + +export default new StatusService(); \ No newline at end of file diff --git a/src/type.d.ts b/src/type.d.ts new file mode 100644 index 0000000..84a3850 --- /dev/null +++ b/src/type.d.ts @@ -0,0 +1 @@ +type Host = { host: string, name: string, alive: boolean, type: 'ping' | 'website' }; \ No newline at end of file