All checks were successful
Test Asgard Runner / test (push) Successful in 3s
- servers.service: sendCommand() now throws InternalServerErrorException on
NATS failure instead of silently succeeding; returns { success, message }
instead of the legacy { output } shape; adds NestJS Logger
- plugins.service: installPlugin() dispatches plugin_install to
corrosion.{license_id}.cmd.server after DB save; NATS failure is logged
but non-fatal so the DB record is preserved regardless
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
107 lines
3.2 KiB
TypeScript
107 lines
3.2 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' };
|
|
}
|
|
}
|