forked from noxious/server
141 lines
4.1 KiB
TypeScript
141 lines
4.1 KiB
TypeScript
import fs from 'fs'
|
|
import express, { Application } from 'express'
|
|
import config from './utilities/config'
|
|
import { getAppPath } from './utilities/files'
|
|
import { createServer as httpServer, Server as HTTPServer } from 'http'
|
|
import { addHttpRoutes } from './utilities/http'
|
|
import cors from 'cors'
|
|
import { Server as SocketServer } from 'socket.io'
|
|
import { Authentication } from './middleware/authentication'
|
|
import { TSocket } from './utilities/types'
|
|
import prisma from './utilities/prisma'
|
|
import { appLogger, watchLogs } from './utilities/logger'
|
|
import ZoneManager from './managers/zoneManager'
|
|
import UserManager from './managers/userManager'
|
|
import CommandManager from './managers/commandManager'
|
|
import CharacterManager from './managers/characterManager'
|
|
import QueueManager from './managers/queueManager'
|
|
import DatetimeManager from './managers/datetimeManager'
|
|
|
|
export class Server {
|
|
private readonly app: Application
|
|
private readonly http: HTTPServer
|
|
private readonly io: SocketServer
|
|
|
|
/**
|
|
* Creates an instance of GameServer.
|
|
*/
|
|
constructor() {
|
|
this.app = express()
|
|
this.app.use(cors())
|
|
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() {
|
|
// Read log file and print to console for debugging
|
|
watchLogs()
|
|
|
|
// Check prisma connection
|
|
try {
|
|
await prisma.$connect()
|
|
appLogger.info('Database connected')
|
|
} catch (error: any) {
|
|
appLogger.error(`Database connection failed: ${error.message}`)
|
|
}
|
|
|
|
// Start the server
|
|
try {
|
|
this.http.listen(config.PORT, config.HOST)
|
|
appLogger.info(`Socket.IO running on port ${config.PORT}`)
|
|
} catch (error: any) {
|
|
appLogger.error(`Socket.IO failed to start: ${error.message}`)
|
|
}
|
|
|
|
// Add http API routes
|
|
await addHttpRoutes(this.app)
|
|
|
|
// Load queue manager
|
|
await QueueManager.boot(this.io)
|
|
|
|
// Load user manager
|
|
await UserManager.boot()
|
|
|
|
// Load datetime manager
|
|
await DatetimeManager.boot(this.io)
|
|
|
|
// Load zoneEditor manager
|
|
await ZoneManager.boot()
|
|
|
|
// Load character manager
|
|
await CharacterManager.boot()
|
|
|
|
// Load command manager
|
|
await CommandManager.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('socketEvents', '', socket)
|
|
} catch (error: any) {
|
|
appLogger.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(filePath)
|
|
if (typeof module.default !== 'function') {
|
|
appLogger.warn(`Unrecognized export in ${file.name}`)
|
|
continue
|
|
}
|
|
|
|
const EventClass = module.default
|
|
const eventInstance = new EventClass(this.io, socket)
|
|
eventInstance.listen()
|
|
} catch (error) {
|
|
appLogger.error(`Error loading event handler ${file.name}: ${error instanceof Error ? error.message : String(error)}`)
|
|
}
|
|
}
|
|
} catch (error) {
|
|
appLogger.error(`Error reading directory: ${error instanceof Error ? error.message : String(error)}`)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Start the server
|
|
const server = new Server()
|
|
server.start()
|
|
|
|
appLogger.info('Server started')
|