1
0
forked from noxious/server
noxious_server/src/server.ts
2024-12-29 01:43:24 +01:00

147 lines
4.3 KiB
TypeScript

import fs from 'fs'
import { createServer as httpServer, Server as HTTPServer } from 'http'
import { pathToFileURL } from 'url'
import cors from 'cors'
import express, { Application } from 'express'
import { Server as SocketServer } from 'socket.io'
import config from '#application/config'
import Database from '#application/database'
import Logger, { LoggerType } from '#application/logger'
import { getAppPath } from '#application/storage'
import { TSocket } from '#application/types'
import ConsoleManager from '#managers/consoleManager'
import DateManager from '#managers/dateManager'
import HttpManager from '#managers/httpManager'
import QueueManager from '#managers/queueManager'
import UserManager from '#managers/userManager'
import WeatherManager from '#managers/weatherManager'
import ZoneManager from '#managers/zoneManager'
import { Authentication } from '#middleware/authentication'
export class Server {
private readonly app: Application
private readonly http: HTTPServer
private readonly io: SocketServer
private readonly logger = Logger.type(LoggerType.APP)
/**
* Creates an instance of GameServer.
*/
constructor() {
this.app = express()
this.app.use(
cors({
origin: config.CLIENT_URL,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // Add supported methods
allowedHeaders: ['Content-Type', 'Authorization'], // Add allowed headers
credentials: true
})
)
this.app.use(express.json())
this.app.use(express.urlencoded({ extended: true }))
this.http = httpServer(this.app)
this.io = new SocketServer(this.http)
this.io.use(Authentication)
}
/**
* Start the server
*/
public async start() {
// Connect to database
try {
await Database.initialize()
} catch (error: any) {
this.logger.error(`Database connection failed: ${error.message}`)
process.exit(1) // Exit if database connection fails
}
// Start the server
try {
this.http.listen(config.PORT, config.HOST)
this.logger.info(`Socket.IO running on port ${config.PORT}`)
} catch (error: any) {
this.logger.error(`Socket.IO failed to start: ${error.message}`)
}
// Load HTTP manager
await HttpManager.boot(this.app)
// Load queue manager
await QueueManager.boot(this.io)
// Load user manager
await UserManager.boot()
// Load date manager
// await DateManager.boot(this.io)
// Load weather manager
// await WeatherManager.boot(this.io)
// Load zoneEditor manager
await ZoneManager.boot()
// Load console manager
await ConsoleManager.boot(this.io)
// Listen for socket connections
this.io.on('connection', this.handleConnection.bind(this))
}
/**
* Handle socket connection
* @param socket
* @private
*/
private async handleConnection(socket: TSocket) {
try {
await this.loadEventHandlers('events', '', socket)
} catch (error: any) {
this.logger.error(`Failed to load event handlers: ${error.message}`)
}
}
private async loadEventHandlers(baseDir: string, subDir: string, socket: TSocket) {
try {
const fullDir = getAppPath(baseDir, subDir)
const files = await fs.promises.readdir(fullDir, { withFileTypes: true })
for (const file of files) {
const filePath = getAppPath(baseDir, subDir, file.name)
if (file.isDirectory()) {
await this.loadEventHandlers(baseDir, `${subDir}/${file.name}`, socket)
continue
}
if (!file.isFile() || (!file.name.endsWith('.ts') && !file.name.endsWith('.js'))) {
continue
}
try {
const module = await import(pathToFileURL(filePath).href)
if (typeof module.default !== 'function') {
this.logger.warn(`Unrecognized export in ${file.name}`)
continue
}
const EventClass = module.default
const eventInstance = new EventClass(this.io, socket)
eventInstance.listen()
} catch (error) {
this.logger.error(`Error loading event handler ${file.name}: ${error instanceof Error ? error.message : String(error)}`)
}
}
} catch (error) {
this.logger.error(`Error reading directory: ${error instanceof Error ? error.message : String(error)}`)
}
}
}
// Start the server
const server = new Server()
server.start()