server-connector.class.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import axios, { AxiosError } from 'axios';
  2. import moment from 'moment';
  3. import { Pool } from 'mysql';
  4. import defaults from '../../../common/defaults.module';
  5. import { Logger } from '../../../common/util/logger.class';
  6. import { FCMController } from './fcm-controller.class';
  7. import { Timer } from '../timer.class';
  8. import { MariaDBDatabase } from './mariadb-database.class';
  9. export class ServerConnector {
  10. private subscriptions: Array<{ id: number; interval: number; server: Server }> = [];
  11. constructor(private pool: Pool) {
  12. const db = new MariaDBDatabase(pool);
  13. (async () => {
  14. try {
  15. await db.open();
  16. const serverList = await db.getAllServerConfigs();
  17. for (const server of serverList) {
  18. let interval = Number(server.config['syncInterval']);
  19. if (Number.isNaN(interval)) interval = defaults.serverSync.interval;
  20. Logger.info('[INFO] Starting Server Sync Connector for', server.title, 'with interval', interval, 'seconds ...');
  21. const id = Timer.instance.subscribe(interval, async () => await this.timerTick(server));
  22. this.subscriptions.push({ id, interval, server });
  23. Logger.info('[INFO] Initial Sync for', server.title, '...');
  24. await this.timerTick(server);
  25. }
  26. } catch (err) {
  27. Logger.error('[FATAL] Initializing ServerConnector failed:', err);
  28. Logger.error('[EXITING]');
  29. process.exit(1);
  30. } finally {
  31. try {
  32. await db.close();
  33. } catch (e) {}
  34. }
  35. })();
  36. }
  37. private async timerTick(server: Server & { errors?: number }) {
  38. Logger.debug('[DEBUG] TICK', new Date(), JSON.stringify(server));
  39. if (process.env.DEV_MODE) return Logger.warn('[WARN] DEV_MODE active - sync inactive.');
  40. let trxHdl: number | undefined = undefined;
  41. const db = new MariaDBDatabase(this.pool);
  42. try {
  43. await db.open();
  44. // Start Transaction, receiving Data and a Transaction Handle
  45. let response = await axios.get(`http://${server.fqdn}:8890/`, { responseType: 'json' });
  46. trxHdl = response.data.hdl;
  47. if (!trxHdl) return; // No data
  48. const data: ReducedData[] = response.data.data.map((entry: any) => ({ ...entry, time: new Date(entry.time) }));
  49. // Process data in DB
  50. await db.insertServerData(server.id, data);
  51. // Commit Transaction
  52. await axios.patch(`http://${server.fqdn}:8890/${trxHdl}`, null, { responseType: 'json' });
  53. if (server.errors) {
  54. // notify [RECOVERY]
  55. try {
  56. await FCMController.instance.sendNotificationToTopic(defaults.fcmTopics.serverData, {
  57. title: `[RECOVERY] ${moment().format('HH:mm')} Server '${server.title}': [OK]`,
  58. body: `[RECOVERY] Server '${server.title}': daemon OK`
  59. });
  60. } catch (err) {
  61. Logger.error('[ERROR] Notification failure:', err);
  62. }
  63. }
  64. server.errors = 0;
  65. } catch (err) {
  66. Logger.error('[ERROR] Server data sync failed:', err);
  67. if (err instanceof AxiosError) {
  68. if (['ECONNREFUSED', 'ECONNABORTED'].includes(err.code ?? '')) {
  69. try {
  70. server.errors = (server.errors ?? 0) + 1;
  71. await FCMController.instance.sendNotificationToTopic(defaults.fcmTopics.serverData, {
  72. title: `[WARN] ${moment().format('HH:mm')} Server '${server.title}': daemon unreachable (${err.code})`,
  73. body: new String(err).toString()
  74. });
  75. } catch (err) {
  76. Logger.error('[ERROR] Notification failure:', err);
  77. }
  78. }
  79. }
  80. if (!!trxHdl) {
  81. Logger.error(`[WARN] Rolling back transaction #${trxHdl} ... `);
  82. const response = await axios.delete(`http://${server.fqdn}:8890/${trxHdl}`, { responseType: 'json' });
  83. if (response.data.ok) {
  84. Logger.error(`[WARN] Rollback succeeded.`);
  85. }
  86. }
  87. // if (!!db) await db.close();
  88. } finally {
  89. try {
  90. await db.close();
  91. } catch (e) {}
  92. }
  93. }
  94. }