Skip to content

Commit

Permalink
refacto(#146): remove websocket client
Browse files Browse the repository at this point in the history
and convert the old WS event emitters to API endpoints for the dashboard
  • Loading branch information
barthofu committed Feb 7, 2024
1 parent 8060043 commit 8db5d31
Show file tree
Hide file tree
Showing 24 changed files with 1,740 additions and 525 deletions.
3 changes: 0 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,5 @@ DATABASE_PASSWORD="tscord123"
API_PORT=4000
API_ADMIN_TOKEN="PUT_A_RANDOM_TOKEN_HERE" # you can generate one here -> https://www.uuidgenerator.net/version1

# websocket
WEBSOCKET_URL="ws://localhost:3001"

# external services
IMGUR_CLIENT_ID="YOUR_IMGUR_CLIENT_ID"
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ Talking about features, here are some of the core features of the template:
- **Scheduler** for cron jobs
- Built-in rich **statistics** system
- Automatic **static assets upload** to [imgur](https://imgur.com/)
- **WebSocket** server with decorators driven events system

This template is also developer friendly and follow strict design patterns to ease its maintenance:
- Written in **Typescript**
Expand Down
1,990 changes: 1,661 additions & 329 deletions package-lock.json

Large diffs are not rendered by default.

27 changes: 13 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,16 @@
"@discordx/importer": "~1.2.1",
"@discordx/pagination": "~3.5.0",
"@discordx/utilities": "~6.1.0",
"@mikro-orm/better-sqlite": "~5.9.7",
"@mikro-orm/cli": "~5.9.7",
"@mikro-orm/core": "~5.9.7",
"@mikro-orm/mariadb": "~5.9.7",
"@mikro-orm/migrations": "~5.9.7",
"@mikro-orm/mongodb": "~5.9.7",
"@mikro-orm/mysql": "~5.9.7",
"@mikro-orm/postgresql": "~5.9.7",
"@mikro-orm/better-sqlite": "~5.6.16",
"@mikro-orm/cli": "~5.6.16",
"@mikro-orm/core": "~5.6.16",
"@mikro-orm/mariadb": "~5.6.16",
"@mikro-orm/migrations": "~5.6.16",
"@mikro-orm/mongodb": "~5.6.16",
"@mikro-orm/mysql": "~5.6.16",
"@mikro-orm/postgresql": "~5.6.16",
"@mikro-orm/sql-highlighter": "~1.0.1",
"@mikro-orm/sqlite": "~5.9.7",
"@mikro-orm/sqlite": "~5.6.16",
"@tsed/common": "^7.61.0",
"@tsed/core": "^7.61.0",
"@tsed/di": "^7.61.0",
Expand All @@ -52,7 +52,7 @@
"cron-validator": "~1.3.1",
"cross-env": "~7.0.3",
"dayjs": "~1.11.10",
"discord-api-types": "~0.37.67",
"discord-api-types": "~0.37.68",
"discord-logs": "~2.2.1",
"discord-oauth2": "~2.12.0",
"discord.js": "~14.14.1",
Expand All @@ -73,8 +73,7 @@
"rentry-pastebin": "~1.3.0",
"rxeta": "~1.1.2",
"saveqlite": "~1.1.2",
"semver": "^7.5.4",
"socket.io-client": "~4.7.4",
"semver": "^7.6.0",
"stacktrace-parser": "~0.1.10",
"swagger-ui-express": "~5.0.0",
"ts-toolbelt": "^9.6.0",
Expand All @@ -88,12 +87,12 @@
"@types/cron": "~2.4.0",
"@types/dateformat": "~5.0.2",
"@types/express": "~4.17.21",
"@types/node": "~20.11.10",
"@types/node": "~20.11.16",
"@types/node-os-utils": "~1.3.4",
"@types/pidusage": "~2.0.5",
"@types/semver": "^7.5.6",
"@types/swagger-ui-express": "~4.1.6",
"chokidar": "~3.5.3",
"chokidar": "~3.6.0",
"ncp": "~2.0.0",
"nodemon": "~3.0.3",
"npm-run-all": "~4.1.5",
Expand Down
4 changes: 2 additions & 2 deletions src/api/controllers/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Required } from "@tsed/schema"
import { BaseGuildTextChannel, BaseGuildVoiceChannel, ChannelType, NewsChannel, PermissionsBitField } from "discord.js"
import { Client, MetadataStorage } from "discordx"

import { Authenticated, BotOnline } from "@api/middlewares"
import { DevAuthenticated, BotOnline } from "@api/middlewares"
import { generalConfig } from "@configs"
import { Guild, User } from "@entities"
import { Database } from "@services"
Expand All @@ -14,7 +14,7 @@ import { getDevs, isDev, isInMaintenance, resolveDependencies, setMaintenance }
@Controller('/bot')
@UseBefore(
BotOnline,
Authenticated
DevAuthenticated
)
export class BotController extends BaseController {

Expand Down
4 changes: 2 additions & 2 deletions src/api/controllers/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { InternalServerError } from "@tsed/exceptions"
import { Required } from "@tsed/schema"
import { injectable } from "tsyringe"

import { Authenticated } from "@api/middlewares"
import { DevAuthenticated } from "@api/middlewares"
import { databaseConfig } from "@configs"
import { Database } from "@services"
import { BaseController } from "@utils/classes"
import { formatDate, resolveDependencies } from "@utils/functions"

@Controller('/database')
@UseBefore(
Authenticated
DevAuthenticated
)
@injectable()
export class DatabaseController extends BaseController {
Expand Down
42 changes: 38 additions & 4 deletions src/api/controllers/health.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import { Controller, Get } from "@tsed/common"
import { Controller, Get, UseBefore } from "@tsed/common"
import { Client } from "discordx"

import { Data } from "@entities"
import { Database, Stats } from "@services"
import { Database, Logger, Stats } from "@services"
import { BaseController } from "@utils/classes"
import { resolveDependencies } from "@utils/functions"
import { isInMaintenance, resolveDependencies } from "@utils/functions"
import { DevAuthenticated } from "../middlewares/devAuthenticated"

@Controller('/health')
export class HealthController extends BaseController {

private client: Client
private db: Database
private stats: Stats
private logger: Logger

constructor() {
super()

resolveDependencies([Client, Database, Stats]).then(([client, db, stats]) => {
resolveDependencies([Client, Database, Stats, Logger]).then(([client, db, stats, logger]) => {
this.client = client
this.db = db
this.stats = stats
this.logger = logger
})
}

Expand Down Expand Up @@ -54,4 +57,35 @@ export class HealthController extends BaseController {

return body
}

@Get('/monitoring')
@UseBefore(
DevAuthenticated
)
async monitoring() {

const body = {
botStatus: {
online: true,
uptime: this.client.uptime,
maintenance: await isInMaintenance()
},
host: await this.stats.getHostUsage(),
pid: await this.stats.getPidUsage(),
latency: this.stats.getLatency()
}

return body
}

@Get('/logs')
@UseBefore(
DevAuthenticated
)
async logs() {

const body = await this.logger.getLastLogs()

return body
}
}
4 changes: 2 additions & 2 deletions src/api/controllers/stats.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Controller, Get, QueryParams, UseBefore } from "@tsed/common"

import { Authenticated } from "@api/middlewares"
import { DevAuthenticated } from "@api/middlewares"
import { Stats } from "@services"
import { BaseController } from "@utils/classes"
import { resolveDependencies } from "@utils/functions"

@Controller('/stats')
@UseBefore(
Authenticated
DevAuthenticated
)
export class StatsController extends BaseController {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const fmaTokenRegex = /mfa\.[\w-]{84}/
const nonFmaTokenRegex = /[\w-]{24}\.[\w-]{6}\.[\w-]{27}/

@Middleware()
export class Authenticated {
export class DevAuthenticated {

private store: Store

Expand Down
2 changes: 1 addition & 1 deletion src/api/middlewares/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './log'
export * from './botOnline'
export * from './authenticated'
export * from './devAuthenticated'
3 changes: 1 addition & 2 deletions src/configs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ export * from './general'
export * from './database'
export * from './logs'
export * from './stats'
export * from './api'
export * from './websocket'
export * from './api'
1 change: 1 addition & 0 deletions src/configs/logs.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const logsConfig: LogsConfigType = {

debug: false, // set the discordx client debug logs
logTailMaxSize: 50, // max size of the last logs kept in memory

// for each type of log, you can precise :
// - if the log should be consoled
Expand Down
4 changes: 0 additions & 4 deletions src/configs/websocket.ts

This file was deleted.

10 changes: 2 additions & 8 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import { Client, DIService, MetadataStorage, tsyringeDependencyRegistryEngine }
import { container } from "tsyringe"

import { Server } from "@api/server"
import { apiConfig, generalConfig, websocketConfig } from "@configs"
import { apiConfig, generalConfig } from "@configs"
import { NoBotTokenError } from "@errors"
import { RequestContext } from '@mikro-orm/core'
import { Database, ErrorHandler, EventManager, ImagesUpload, Logger, PluginsManager, Store, WebSocket } from "@services"
import { Database, ErrorHandler, EventManager, ImagesUpload, Logger, PluginsManager, Store } from "@services"
import { initDataTable, resolveDependency } from "@utils/functions"
import chalk from 'chalk'
import { clientConfig } from "./client"
Expand Down Expand Up @@ -146,12 +146,6 @@ async function init() {
await server.start()
}

// connect to the dashboard websocket
if (websocketConfig.enabled) {
const webSocket = await resolveDependency(WebSocket)
await webSocket.init(client.user?.id || null)
}

// upload images to imgur if configured
if (process.env.IMGUR_CLIENT_ID && generalConfig.automaticUploadImagesToImgur) {
const imagesUpload = await resolveDependency(ImagesUpload)
Expand Down
21 changes: 9 additions & 12 deletions src/services/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { delay, inject, singleton } from "tsyringe"

import * as controllers from "@api/controllers"
import { apiConfig, logsConfig } from "@configs"
import { Pastebin, PluginsManager, Scheduler, Store, WebSocket } from "@services"
import { Pastebin, PluginsManager, Scheduler, Store } from "@services"
import { fileOrDirectoryExists, formatDate, getTypeOfInteraction, numberAlign, oneLine, resolveAction, resolveChannel, resolveDependency, resolveGuild, resolveUser, validString } from "@utils/functions"

const defaultConsole = { ...console }
Expand All @@ -33,12 +33,12 @@ export class Logger {
"MODAL_SUBMIT_INTERACTION": "Modal submit",
}
private spinner = ora()
private lastLogsTail: string[] = []

constructor(
@inject(delay(() => Client)) private client: Client,
@inject(delay(() => Scheduler)) private scheduler: Scheduler,
@inject(delay(() => Store)) private store: Store,
@inject(delay(() => WebSocket)) private ws: WebSocket,
@inject(delay(() => Pastebin)) private pastebin: Pastebin,
@inject(delay(() => PluginsManager)) private pluginsManager: PluginsManager
) {
Expand Down Expand Up @@ -70,7 +70,9 @@ export class Logger {

defaultConsole[level](templatedMessage)

this.websocket(level, message)
// save the last logs tail queue
if (this.lastLogsTail.length >= logsConfig.logTailMaxSize) this.lastLogsTail.shift()
this.lastLogsTail.push(message)
}

/**
Expand Down Expand Up @@ -118,15 +120,6 @@ export class Logger {
}
}

websocket(level: typeof this.levels[number] = 'info', message: string) {

// send the log to all connected websocket clients
this.ws.broadcast('log', {
level,
message: message
})
}

// =================================
// =========== Shortcut ============
// =================================
Expand Down Expand Up @@ -377,6 +370,10 @@ export class Logger {
// =================================
// ============= Other =============
// =================================

getLastLogs() {
return this.lastLogsTail
}

startSpinner(text: string) {

Expand Down
35 changes: 5 additions & 30 deletions src/services/Stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import osu from "node-os-utils"
import pidusage from "pidusage"
import { delay, inject, singleton } from "tsyringe"

import { statsConfig, websocketConfig } from "@configs"
import { Schedule, WSOn } from "@decorators"
import { statsConfig } from "@configs"
import { Schedule } from "@decorators"
import { Guild, Stat, User } from "@entities"
import { Database, WebSocket } from "@services"
import { datejs, formatDate, getTypeOfInteraction, isInMaintenance, resolveAction, resolveChannel, resolveGuild, resolveUser } from "@utils/functions"
import { Database } from "@services"
import { datejs, formatDate, getTypeOfInteraction, resolveAction, resolveChannel, resolveGuild, resolveUser } from "@utils/functions"

const allInteractions = {
$or: [
Expand All @@ -28,7 +28,6 @@ export class Stats {
constructor(
private db: Database,
@inject(delay(() => Client)) private client: Client,
@inject(delay(() => WebSocket)) private ws: WebSocket
) {
this.statsRepo = this.db.get(Stat)
}
Expand Down Expand Up @@ -379,7 +378,7 @@ export class Stats {
ping: this.client.ws.ping
}
}

/**
* Run each day at 23:59 to update daily stats.
*/
Expand All @@ -394,28 +393,4 @@ export class Stats {
}
}

// ORDER OF DECORATORS IS IMPORTANT!
@WSOn('getHealth')
@Schedule('*/5 * * * * *')
async sendWebSocketHealth(response?: WSResponseFunction) {

if (websocketConfig.enabled) {

const data = {
botStatus: {
online: true,
uptime: this.client.uptime,
maintenance: await isInMaintenance()
},
host: await this.getHostUsage(),
pid: await this.getPidUsage(),
latency: this.getLatency()
}

if (response) response('monitoring', data)
else this.ws.broadcast('monitoring', data)
}

}

}
Loading

0 comments on commit 8db5d31

Please sign in to comment.