All checks were successful
Test Asgard Runner / test (push) Successful in 3s
- players: Primary data from player_sessions (online status, playtime aggregates);
ban/unban status overlaid from player_actions latest action per steam_id.
Register PlayerSession entity in PlayersModule. Extend NATS forwarding to
include 'unban' alongside kick and ban.
- analytics: Fix retention period boundary bug — sessions were queried with only
a lower-bound filter (MoreThan), causing all future cycles to bleed into earlier
wipe windows. Replaced with Between(wipeDate, endDate) for correct isolation.
- status: Replace hardcoded player_count=0/max_players=0 with live data from
most-recent server_stats row per license. Register ServerStats entity in
StatusModule. Falls back to 0 gracefully when no stats exist yet.
- maps: File buffer was computed and discarded — never written to disk.
Now writes to /app/map_data/{licenseId}/{timestamp}_{filename} (tenant-isolated,
docker volume map_data). Creates directories with mkdirSync(recursive:true).
Logs success/failure via NestJS Logger. Throws 500 on disk write failure
instead of silently losing data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
62 lines
2.2 KiB
TypeScript
62 lines
2.2 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
import { Repository } from 'typeorm';
|
|
import { PublicSiteConfig } from '../../entities/public-site-config.entity';
|
|
import { ServerConnection } from '../../entities/server-connection.entity';
|
|
import { ServerStats } from '../../entities/server-stats.entity';
|
|
import { License } from '../../entities/license.entity';
|
|
|
|
@Injectable()
|
|
export class StatusService {
|
|
constructor(
|
|
@InjectRepository(PublicSiteConfig)
|
|
private readonly publicSiteRepo: Repository<PublicSiteConfig>,
|
|
@InjectRepository(ServerConnection)
|
|
private readonly serverConnectionRepo: Repository<ServerConnection>,
|
|
@InjectRepository(ServerStats)
|
|
private readonly serverStatsRepo: Repository<ServerStats>,
|
|
@InjectRepository(License)
|
|
private readonly licenseRepo: Repository<License>,
|
|
) {}
|
|
|
|
async getStatus() {
|
|
const publicConfigs = await this.publicSiteRepo.find({
|
|
where: { show_on_status_page: true },
|
|
relations: ['license'],
|
|
});
|
|
|
|
const servers = await Promise.all(
|
|
publicConfigs.map(async (config) => {
|
|
const license = await this.licenseRepo.findOne({
|
|
where: { id: config.license_id },
|
|
});
|
|
|
|
const connection = await this.serverConnectionRepo.findOne({
|
|
where: { license_id: config.license_id },
|
|
});
|
|
|
|
// Fetch the most recent stats row for this server to get live player counts
|
|
const latestStats = await this.serverStatsRepo.findOne({
|
|
where: { license_id: config.license_id },
|
|
order: { recorded_at: 'DESC' },
|
|
});
|
|
|
|
return {
|
|
server_name: license?.server_name || license?.subdomain || 'Unknown Server',
|
|
subdomain: license?.subdomain || null,
|
|
status: connection?.connection_status || 'offline',
|
|
player_count: latestStats?.player_count ?? 0,
|
|
max_players: latestStats?.max_players ?? 0,
|
|
steam_connect_url: config.steam_connect_url,
|
|
motd: config.motd,
|
|
discord_invite_url: config.discord_invite_url,
|
|
theme_color: config.theme_color,
|
|
description: config.status_page_description,
|
|
};
|
|
}),
|
|
);
|
|
|
|
return { servers };
|
|
}
|
|
}
|