import { Injectable, NotFoundException, InternalServerErrorException, Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { ServerConnection } from '../../entities/server-connection.entity'; import { ServerConfig } from '../../entities/server-config.entity'; import { NatsService } from '../../services/nats.service'; import { UpdateServerConfigDto } from './dto/update-config.dto'; import { DeployServerDto } from './dto/deploy-server.dto'; @Injectable() export class ServersService { private readonly logger = new Logger(ServersService.name); constructor( @InjectRepository(ServerConnection) private readonly connectionRepo: Repository, @InjectRepository(ServerConfig) private readonly configRepo: Repository, private readonly natsService: NatsService, ) {} /** * Get server connection and config for a license. * Returns null fields if no server has been set up yet. */ async getServer(licenseId: string) { const connection = await this.connectionRepo.findOne({ where: { license_id: licenseId }, }); const config = await this.configRepo.findOne({ where: { license_id: licenseId }, }); return { connection: connection || null, config: config || null, setup_required: !connection || !config, }; } /** * Update server configuration */ async updateConfig(licenseId: string, dto: UpdateServerConfigDto) { const config = await this.configRepo.findOne({ where: { license_id: licenseId }, }); if (!config) { throw new NotFoundException('Server config not found'); } // Apply updates Object.assign(config, dto); config.updated_at = new Date(); return await this.configRepo.save(config); } /** * Send a console command to the server via NATS */ async sendCommand(licenseId: string, command: string) { try { await this.natsService.sendServerCommand(licenseId, 'command', { command }); this.logger.log(`Console command dispatched for license ${licenseId}: ${command}`); } catch (err) { this.logger.error(`Failed to dispatch console command for license ${licenseId}: ${(err as Error).message}`); throw new InternalServerErrorException('Failed to dispatch command to server'); } return { success: true, message: 'Command dispatched' }; } /** * Start the server via NATS */ async startServer(licenseId: string) { await this.natsService.sendServerCommand(licenseId, 'start'); return { message: 'Start command sent' }; } /** * Stop the server via NATS */ async stopServer(licenseId: string) { await this.natsService.sendServerCommand(licenseId, 'stop'); return { message: 'Stop command sent' }; } /** * Restart the server via NATS */ async restartServer(licenseId: string) { await this.natsService.sendServerCommand(licenseId, 'restart'); return { message: 'Restart command sent' }; } /** * Deploy Rust server via companion agent */ async deployServer(licenseId: string, dto: DeployServerDto) { await this.natsService.sendDeployCommand(licenseId, { ...dto }); return { message: 'Deployment started' }; } /** * Install Oxide/uMod via companion agent */ async installOxide(licenseId: string) { await this.natsService.sendOxideInstallCommand(licenseId); return { message: 'Oxide installation started' }; } }