surveillance.service.ts 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. /**
  2. * Lego 09 / Lego 11 — Surveillance HUD Service
  3. *
  4. * Opens a persistent Socket.io connection to NestJS /monitor namespace.
  5. * Emits monitor:subscribe on connect and keeps the tunnel alive indefinitely.
  6. * Exposes signals for the PerformanceHUD and chatbot status indicators.
  7. *
  8. * Exposes nestStatus (ONLINE/OFFLINE) derived from socket connection state.
  9. */
  10. import { Injectable, signal, computed, OnDestroy } from '@angular/core';
  11. import { io, Socket } from 'socket.io-client';
  12. import { environment } from '../../environments/environment';
  13. export interface MonitorPayload {
  14. service: string;
  15. pid: number;
  16. cpu: number;
  17. memory: number; // bytes
  18. timestamp: string;
  19. }
  20. @Injectable({ providedIn: 'root' })
  21. export class SurveillanceService implements OnDestroy {
  22. /** Live metrics — HUD reads this signal directly */
  23. readonly metrics = signal<MonitorPayload[]>([]);
  24. readonly connected = signal<boolean>(false);
  25. /** Derived status string — consumed by Scanner and HUD */
  26. readonly nestStatus = computed<'ONLINE' | 'OFFLINE'>(() =>
  27. this.connected() ? 'ONLINE' : 'OFFLINE'
  28. );
  29. private socket: Socket;
  30. constructor() {
  31. // Persistent tunnel — opened on service construction (app boot)
  32. this.socket = io(`${environment.nestWsUrl}/monitor`, {
  33. transports: ['websocket'],
  34. reconnection: true,
  35. reconnectionDelay: 1000,
  36. secure: true,
  37. rejectUnauthorized: false,
  38. });
  39. this.socket.on('connect', () => {
  40. this.connected.set(true);
  41. this.socket.emit('monitor:subscribe');
  42. });
  43. this.socket.on('disconnect', () => {
  44. this.connected.set(false);
  45. });
  46. this.socket.on('monitor:data', (payload: MonitorPayload[]) => {
  47. this.metrics.set(payload);
  48. });
  49. }
  50. ngOnDestroy() {
  51. this.socket.disconnect();
  52. }
  53. formatBytes(bytes: number): string {
  54. if (bytes === 0) return '0 B';
  55. const mb = bytes / (1024 * 1024);
  56. return `${mb.toFixed(1)} MB`;
  57. }
  58. }