Source: services/zWebService.ts

import { zConfigModule } from '../configs';
import { Observable, of, throwError } from 'rxjs';
import { zTranslateService } from './zTranslateService';
import { Express } from 'express';
import cors from 'cors';
import helmet from 'helmet';
import bodyParser from 'body-parser';
import express from 'express';
import { catchError, delay, retryWhen, tap } from 'rxjs/operators';

/**
 * Service that contains the functions related to the web service.
 * @author Ivan Antunes <ivanantnes75@gmail.com>
 * @copyright Ivan Antunes 2021
 */
export class zWebService {

  /**
   * Stores zWebService Service Instance.
   * @author Ivan Antunes <ivanantnes75@gmail.com>
   * @copyright Ivan Antunes 2021
   */
  private static instance: zWebService | null;


  /**
   * Stores instance zTranslateService.
   * @author Ivan Antunes <ivanantnes75@gmail.com>
   * @copyright Ivan Antunes 2021
   */
  private tService = zTranslateService.getInstance();

  /**
   * Express instance containing the server.
   * @author Ivan Antunes <ivanantnes75@gmail.com>
   * @copyright Ivan Antunes 2021
   */
  private server: Express | null = null;

  /**
   * Stores if initialized service.
   * @author Ivan Antunes <ivanantnes75@gmail.com>
   * @copyright Ivan Antunes 2021
   */
  private isInitialized = false;

  /**
   * Start Server in Service
   * @author Ivan Antunes <ivanantnes75@gmail.com>
   * @copyright Ivan Antunes 2021
   */
  private constructor() {
    const app = express();

    this.setConfigServer(app).subscribe((currentApp) => {

      this.server = currentApp;

      this.server.listen(zConfigModule.MOD_SERVER_PORT, () => {
        console.log(`${this.tService.t('web_server_start')} ${zConfigModule.MOD_SERVER_PORT}`);
        this.isInitialized = true;
      });

    }, (err) => {
      throw new Error(`${this.tService.t('web_server_failed')} ${err}`);
    });

  }

  /**
   * Function used to get instance of zWebService
   * @returns zWebService
   * @author Ivan Antunes <ivanantnes75@gmail.com>
   * @copyright Ivan Antunes 2021
   */
  public static getInstance(): zWebService {

    if (!zWebService.instance) {
      zWebService.instance = new zWebService();
    }

    return zWebService.instance;

  }

  /**
   * Function used to destroy instance of zWebService.
   * @author Ivan Antunes <ivanantnes75@gmail.com>
   * @copyright Ivan Antunes 2021
   */
  public static destroyInstance(): void {

    zWebService.instance = null;

  }

  /**
   * Configure server settings
   * @param {Express} server - Server instance
   * @returns Observable<Express>
   * @author Ivan Antunes <ivanantnes75@gmail.com>
   * @copyright Ivan Antunes 2021
   */
  private setConfigServer(server: Express): Observable<Express> {
    server.use(cors({maxAge: 86000}));

    server.use(helmet());

    server.use(bodyParser.json());
    server.use(bodyParser.urlencoded({
      extended: true
    }));

    return of(server);
  }

  /**
   * Start the server
   * @returns Observable<Express>
   * @author Ivan Antunes <ivanantnes75@gmail.com>
   * @copyright Ivan Antunes 2021
   */
  public startWebService(): Observable<Express> {

    return (new Observable<Express>((obs) => {

      if (this.isInitialized) {
        obs.next(this.server as Express);
        return obs.complete();
      } else {
        return obs.error(this.tService.t('web_server_not_initialized'));
      }

    })).pipe(
      catchError((err) => {
        console.log(err);
        return throwError(err);
      }),
      retryWhen((err) => err.pipe(
        tap(() => console.log(this.tService.t('web_server_try_again'))),
        delay(5000)
      ))
    );
  }


}