fix: Wire real data sources across players, analytics, status, and maps services
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>
This commit is contained in:
Vantz Stockwell
2026-02-21 16:01:45 -05:00
parent 7bf3e5639e
commit 9240feedaf
6 changed files with 124 additions and 36 deletions

View File

@@ -4,11 +4,12 @@ import { StatusController } from './status.controller';
import { StatusService } from './status.service';
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';
@Module({
imports: [
TypeOrmModule.forFeature([PublicSiteConfig, ServerConnection, License]),
TypeOrmModule.forFeature([PublicSiteConfig, ServerConnection, ServerStats, License]),
],
controllers: [StatusController],
providers: [StatusService],

View File

@@ -3,6 +3,7 @@ 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()
@@ -12,6 +13,8 @@ export class StatusService {
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>,
) {}
@@ -32,12 +35,18 @@ export class StatusService {
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?.subdomain || 'Unknown Server',
server_name: license?.server_name || license?.subdomain || 'Unknown Server',
subdomain: license?.subdomain || null,
status: connection?.connection_status || 'offline',
player_count: 0, // Would need real-time data
max_players: 0,
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,