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>
115 lines
3.4 KiB
TypeScript
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' };
|
|
}
|
|
}
|