import net from 'node:net' import type { RowDataPacket } from 'mysql2' import { db, DB } from './db' export interface Noticia { id: number titulo: string fecha: string | null contenido: string enlace: string | null } export interface ServerStatus { server_name: string | null address: string | null expansion: string online_characters: number status: 'Online' | 'Offline' world_status: 'Online' | 'Offline' } // Puerto del worldserver (AzerothCore) para el estado del reino. const WORLD_PORT = 8085 /** Etiqueta de expansión por build del cliente (incluye WoW Classic; el nuestro = 3.4.3 = 54261). */ export function expansionFromGamebuild(gamebuild: number): string { if (gamebuild === 12340) return 'WotLK' if (gamebuild >= 44000 && gamebuild <= 54261) return 'WotLK Classic' if (gamebuild === 15595) return 'Cataclysm' if (gamebuild >= 54262 && gamebuild <= 60000) return 'Cataclysm Classic' return 'Unknown' } /** * Noticias localizadas. Con `locale='en'` usa `titulo_en`/`contenido_en` si * existen; si están vacías, cae a la versión en español (título y contenido de * forma independiente). El texto original (titulo/contenido) siempre es ES. */ export async function getNoticias(locale = 'es', limit = 50): Promise { const [rows] = await db(DB.default).query( 'SELECT id, titulo, titulo_en, contenido, contenido_en, fecha_publicacion, enlace FROM noticia ORDER BY fecha_publicacion DESC LIMIT ?', [limit], ) const en = locale === 'en' return rows.map((r) => ({ id: r.id, titulo: en && r.titulo_en ? r.titulo_en : r.titulo, fecha: r.fecha_publicacion ? new Date(r.fecha_publicacion).toISOString() : null, contenido: en && r.contenido_en ? r.contenido_en : r.contenido, enlace: r.enlace || null, })) } async function getOnlineCount(): Promise { try { const [rows] = await db(DB.characters).query( 'SELECT COUNT(*) AS n FROM characters WHERE online = 1', ) return Number(rows[0]?.n ?? 0) } catch { // La BD de personajes (AzerothCore) puede no estar poblada todavía. return 0 } } function checkServerStatus(host: string, port: number, timeout = 1000): Promise { return new Promise((resolve) => { if (!host || host === 'N/A') return resolve(false) const socket = new net.Socket() const done = (ok: boolean) => { socket.destroy() resolve(ok) } socket.setTimeout(timeout) socket.once('connect', () => done(true)) socket.once('timeout', () => done(false)) socket.once('error', () => done(false)) socket.connect(port, host) }) } export async function getServerStatus(): Promise { const [rows] = await db(DB.default).query( 'SELECT name, address, port, gamebuild FROM serverselection LIMIT 1', ) const s = rows[0] if (!s) return null const [online, up, worldUp] = await Promise.all([ getOnlineCount(), checkServerStatus(s.address, s.port), checkServerStatus(s.address, WORLD_PORT), ]) return { server_name: s.name, address: s.address, expansion: expansionFromGamebuild(s.gamebuild), online_characters: online, status: up ? 'Online' : 'Offline', world_status: worldUp ? 'Online' : 'Offline', } }