forked from noxious/server
Moved more socket logic into socket manager for easier DX
This commit is contained in:
parent
a5c941cbb0
commit
ba12674e7c
@ -4,6 +4,7 @@ import { CommandRegistry } from '#application/console/commandRegistry'
|
|||||||
import { ConsolePrompt } from '#application/console/consolePrompt'
|
import { ConsolePrompt } from '#application/console/consolePrompt'
|
||||||
import { LogReader } from '#application/console/logReader'
|
import { LogReader } from '#application/console/logReader'
|
||||||
import Logger, { LoggerType } from '#application/logger'
|
import Logger, { LoggerType } from '#application/logger'
|
||||||
|
import SocketManager from '#managers/socketManager'
|
||||||
|
|
||||||
export class ConsoleManager {
|
export class ConsoleManager {
|
||||||
private readonly logger = Logger.type(LoggerType.COMMAND)
|
private readonly logger = Logger.type(LoggerType.COMMAND)
|
||||||
@ -19,8 +20,8 @@ export class ConsoleManager {
|
|||||||
this.logReader = new LogReader(process.cwd())
|
this.logReader = new LogReader(process.cwd())
|
||||||
}
|
}
|
||||||
|
|
||||||
public async boot(io: Server): Promise<void> {
|
public async boot(): Promise<void> {
|
||||||
this.io = io
|
this.io = SocketManager.getIO()
|
||||||
|
|
||||||
await this.registry.loadCommands()
|
await this.registry.loadCommands()
|
||||||
this.logReader.start()
|
this.logReader.start()
|
||||||
|
@ -8,6 +8,7 @@ import config from '#application/config'
|
|||||||
import Logger, { LoggerType } from '#application/logger'
|
import Logger, { LoggerType } from '#application/logger'
|
||||||
import { getAppPath } from '#application/storage'
|
import { getAppPath } from '#application/storage'
|
||||||
import { TSocket } from '#application/types'
|
import { TSocket } from '#application/types'
|
||||||
|
import SocketManager from '#managers/socketManager'
|
||||||
|
|
||||||
class QueueManager {
|
class QueueManager {
|
||||||
private connection!: IORedis
|
private connection!: IORedis
|
||||||
@ -16,8 +17,8 @@ class QueueManager {
|
|||||||
private io!: SocketServer
|
private io!: SocketServer
|
||||||
private logger = Logger.type(LoggerType.QUEUE)
|
private logger = Logger.type(LoggerType.QUEUE)
|
||||||
|
|
||||||
public async boot(io: SocketServer) {
|
public async boot() {
|
||||||
this.io = io
|
this.io = SocketManager.getIO()
|
||||||
|
|
||||||
this.connection = new IORedis(config.REDIS_URL, {
|
this.connection = new IORedis(config.REDIS_URL, {
|
||||||
maxRetriesPerRequest: null
|
maxRetriesPerRequest: null
|
||||||
|
@ -1,27 +1,53 @@
|
|||||||
|
import { Server as SocketServer } from 'socket.io'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import { pathToFileURL } from 'url'
|
import { pathToFileURL } from 'url'
|
||||||
|
import { Server as HTTPServer } from 'http'
|
||||||
import { Server as SocketServer } from 'socket.io'
|
import { Application } from 'express'
|
||||||
|
|
||||||
import Logger, { LoggerType } from '#application/logger'
|
import Logger, { LoggerType } from '#application/logger'
|
||||||
import { getAppPath } from '#application/storage'
|
import { getAppPath } from '#application/storage'
|
||||||
import { TSocket } from '#application/types'
|
import { TSocket } from '#application/types'
|
||||||
|
import config from '#application/config'
|
||||||
|
import { Authentication } from '#middleware/authentication'
|
||||||
|
|
||||||
class SocketManager {
|
class SocketManager {
|
||||||
private io: any
|
private io: SocketServer | null = null
|
||||||
private logger = Logger.type(LoggerType.APP)
|
private readonly logger = Logger.type(LoggerType.APP)
|
||||||
|
|
||||||
public async boot(io: SocketServer) {
|
/**
|
||||||
this.io = io
|
* Initialize Socket.IO server
|
||||||
io.on('connection', this.handleConnection.bind(this))
|
*/
|
||||||
|
public async boot(app: Application, http: HTTPServer): Promise<void> {
|
||||||
|
this.io = new SocketServer(http, {
|
||||||
|
cors: {
|
||||||
|
origin: config.CLIENT_URL,
|
||||||
|
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
||||||
|
allowedHeaders: ['Content-Type', 'Authorization'],
|
||||||
|
credentials: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Apply authentication middleware
|
||||||
|
this.io.use(Authentication)
|
||||||
|
|
||||||
|
// Set up connection handler
|
||||||
|
this.io.on('connection', this.handleConnection.bind(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Socket.IO server instance
|
||||||
|
*/
|
||||||
|
public getIO(): SocketServer {
|
||||||
|
if (!this.io) {
|
||||||
|
throw new Error('Socket.IO has not been initialized')
|
||||||
|
}
|
||||||
|
return this.io
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle socket connection
|
* Handle socket connection
|
||||||
* @param socket
|
|
||||||
* @private
|
|
||||||
*/
|
*/
|
||||||
private async handleConnection(socket: TSocket) {
|
private async handleConnection(socket: TSocket): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await this.loadEventHandlers('events', '', socket)
|
await this.loadEventHandlers('events', '', socket)
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
@ -29,7 +55,10 @@ class SocketManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async loadEventHandlers(baseDir: string, subDir: string, socket: TSocket) {
|
/**
|
||||||
|
* Load event handlers recursively from the events directory
|
||||||
|
*/
|
||||||
|
private async loadEventHandlers(baseDir: string, subDir: string, socket: TSocket): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const fullDir = getAppPath(baseDir, subDir)
|
const fullDir = getAppPath(baseDir, subDir)
|
||||||
const files = await fs.promises.readdir(fullDir, { withFileTypes: true })
|
const files = await fs.promises.readdir(fullDir, { withFileTypes: true })
|
||||||
@ -64,6 +93,20 @@ class SocketManager {
|
|||||||
this.logger.error(`Error reading directory: ${error instanceof Error ? error.message : String(error)}`)
|
this.logger.error(`Error reading directory: ${error instanceof Error ? error.message : String(error)}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit event to all connected clients
|
||||||
|
*/
|
||||||
|
public emit(event: string, ...args: any[]): void {
|
||||||
|
this.getIO().emit(event, ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit event to specific room
|
||||||
|
*/
|
||||||
|
public emitToRoom(room: string, event: string, ...args: any[]): void {
|
||||||
|
this.getIO().to(room).emit(event, ...args)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new SocketManager()
|
export default new SocketManager()
|
@ -1,8 +1,6 @@
|
|||||||
import { createServer as httpServer, Server as HTTPServer } from 'http'
|
import { createServer as httpServer, Server as HTTPServer } from 'http'
|
||||||
|
|
||||||
import cors from 'cors'
|
|
||||||
import express, { Application } from 'express'
|
import express, { Application } from 'express'
|
||||||
import { Server as SocketServer } from 'socket.io'
|
import cors from 'cors'
|
||||||
|
|
||||||
import config from '#application/config'
|
import config from '#application/config'
|
||||||
import Database from '#application/database'
|
import Database from '#application/database'
|
||||||
@ -15,77 +13,45 @@ import SocketManager from '#managers/socketManager'
|
|||||||
import UserManager from '#managers/userManager'
|
import UserManager from '#managers/userManager'
|
||||||
import WeatherManager from '#managers/weatherManager'
|
import WeatherManager from '#managers/weatherManager'
|
||||||
import ZoneManager from '#managers/zoneManager'
|
import ZoneManager from '#managers/zoneManager'
|
||||||
import { Authentication } from '#middleware/authentication'
|
|
||||||
|
|
||||||
export class Server {
|
export class Server {
|
||||||
private readonly app: Application
|
private readonly app: Application
|
||||||
private readonly http: HTTPServer
|
private readonly http: HTTPServer
|
||||||
private readonly io: SocketServer
|
|
||||||
private readonly logger = Logger.type(LoggerType.APP)
|
private readonly logger = Logger.type(LoggerType.APP)
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an instance of GameServer.
|
|
||||||
*/
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.app = express()
|
this.app = express()
|
||||||
this.app.use(
|
this.app.use(cors())
|
||||||
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.json())
|
||||||
this.app.use(express.urlencoded({ extended: true }))
|
this.app.use(express.urlencoded({ extended: true }))
|
||||||
this.http = httpServer(this.app)
|
this.http = httpServer(this.app)
|
||||||
this.io = new SocketServer(this.http)
|
|
||||||
this.io.use(Authentication)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public async start(): Promise<void> {
|
||||||
* Start the server
|
|
||||||
*/
|
|
||||||
public async start() {
|
|
||||||
// Connect to database
|
|
||||||
try {
|
try {
|
||||||
|
// Initialize database
|
||||||
await Database.initialize()
|
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
|
// Start HTTP server
|
||||||
try {
|
|
||||||
this.http.listen(config.PORT, config.HOST)
|
this.http.listen(config.PORT, config.HOST)
|
||||||
this.logger.info(`Socket.IO running on port ${config.PORT}`)
|
this.logger.info(`Server running on port ${config.PORT}`)
|
||||||
|
|
||||||
|
// Initialize managers
|
||||||
|
await Promise.all([
|
||||||
|
HttpManager.boot(this.app),
|
||||||
|
SocketManager.boot(this.app, this.http),
|
||||||
|
QueueManager.boot(),
|
||||||
|
UserManager.boot(),
|
||||||
|
// DateManager.boot(SocketManager.getIO()),
|
||||||
|
// WeatherManager.boot(SocketManager.getIO()),
|
||||||
|
ZoneManager.boot(),
|
||||||
|
ConsoleManager.boot()
|
||||||
|
])
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
this.logger.error(`Socket.IO failed to start: ${error.message}`)
|
this.logger.error(`Server failed to start: ${error.message}`)
|
||||||
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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)
|
|
||||||
|
|
||||||
// Load socket manager
|
|
||||||
await SocketManager.boot(this.io)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user