Files
corrosion-admin-panel/backend-nest/src/modules/servers/servers.service.ts
Vantz Stockwell 6461417b50
All checks were successful
Build Companion Agent / build (push) Successful in 24s
Test Asgard Runner / test (push) Successful in 3s
feat: Add one-click Oxide/uMod installer — backend + frontend
POST /servers/install-oxide endpoint, NATS bridge for oxide.status,
server store installOxide method, ServerView Install Oxide card with
progress tracker matching the Deploy card pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 01:56:59 -05:00

115 lines
3.4 KiB
TypeScript

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<ServerConnection>,
@InjectRepository(ServerConfig)
private readonly configRepo: Repository<ServerConfig>,
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' };
}
}