diff --git a/src/api/routes.ts b/src/api/routes.ts index 0e09d5f..1f6ebc3 100644 --- a/src/api/routes.ts +++ b/src/api/routes.ts @@ -171,10 +171,35 @@ router.get('/subscribe_events', middleware.wsRateLimiter, (req, res) => { } }); -// SSE stats endpoint +/** + * SSE Statistics Endpoint + * Returns detailed statistics about SSE connections and subscriptions. + * + * @route GET /get_sse_stats + * @authentication Required - Bearer token + * @returns {Object} Statistics object containing: + * - total_clients: Total number of connected clients + * - authenticated_clients: Number of authenticated clients + * - total_subscriptions: Total number of active subscriptions + * - clients_by_connection_time: Client counts by connection duration + * - total_entities_tracked: Number of entities being tracked + * - subscriptions: Lists of entity, event, and domain subscriptions + */ router.get('/get_sse_stats', middleware.authenticate, (_req, res) => { - const stats = sseManager.getStatistics(); - res.json(stats); + try { + const stats = sseManager.getStatistics(); + res.json({ + success: true, + timestamp: new Date().toISOString(), + data: stats + }); + } catch (error) { + res.status(500).json({ + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred', + timestamp: new Date().toISOString() + }); + } }); export default router; \ No newline at end of file diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts index a0273f6..3a4be28 100644 --- a/src/interfaces/index.ts +++ b/src/interfaces/index.ts @@ -30,31 +30,19 @@ export interface CommandParams { humidity?: number; } +// Re-export Home Assistant types +export type { + HassInstance, + HassStates, + HassServices, + HassConnection, + HassService, + HassEvent, + HassEntity, + HassState +} from './hass.js'; + // Home Assistant interfaces -export interface HassEntity { - entity_id: string; - state: string; - attributes: Record; - last_changed?: string; - last_updated?: string; - context?: { - id: string; - parent_id?: string; - user_id?: string; - }; -} - -export interface HassState { - entity_id: string; - state: string; - attributes: { - friendly_name?: string; - description?: string; - [key: string]: any; - }; -} - -// Add-on interfaces export interface HassAddon { name: string; slug: string; @@ -179,7 +167,4 @@ export interface AutomationConfigParams { condition?: any[]; action: any[]; }; -} - -// Re-export all Home Assistant types -export * from './hass.js'; \ No newline at end of file +} \ No newline at end of file diff --git a/src/sse/index.ts b/src/sse/index.ts index 11f4e48..8899ade 100644 --- a/src/sse/index.ts +++ b/src/sse/index.ts @@ -1,5 +1,5 @@ import { EventEmitter } from 'events'; -import { HassEntity, HassEvent, StateChangedEvent } from '../types/hass.js'; +import { HassEntity, HassEvent } from '../interfaces/hass.js'; import { TokenManager } from '../security/index.js'; interface RateLimit { @@ -345,17 +345,29 @@ export class SSEManager extends EventEmitter { less_than_1h: 0, more_than_1h: 0 }, - total_entities_tracked: this.entityStates.size + total_entities_tracked: this.entityStates.size, + subscriptions: { + entities: new Set(), + events: new Set(), + domains: new Set() + } }; for (const client of this.clients.values()) { if (client.authenticated) stats.authenticated_clients++; + // Count subscriptions stats.total_subscriptions += client.subscriptions.entities.size + client.subscriptions.events.size + client.subscriptions.domains.size; + // Add to subscription sets + client.subscriptions.entities.forEach(entity => stats.subscriptions.entities.add(entity)); + client.subscriptions.events.forEach(event => stats.subscriptions.events.add(event)); + client.subscriptions.domains.forEach(domain => stats.subscriptions.domains.add(domain)); + + // Calculate connection duration const connectionDuration = now - client.connectionTime; if (connectionDuration < 60000) stats.clients_by_connection_time.less_than_1m++; else if (connectionDuration < 300000) stats.clients_by_connection_time.less_than_5m++; @@ -363,7 +375,15 @@ export class SSEManager extends EventEmitter { else stats.clients_by_connection_time.more_than_1h++; } - return stats; + // Convert Sets to Arrays for JSON serialization + return { + ...stats, + subscriptions: { + entities: Array.from(stats.subscriptions.entities), + events: Array.from(stats.subscriptions.events), + domains: Array.from(stats.subscriptions.domains) + } + }; } }