feat: add initial HTTP/2 support to ui server (mutually exclusive for now)
authorJérôme Benoit <jerome.benoit@sap.com>
Sun, 30 Jul 2023 13:38:25 +0000 (15:38 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Sun, 30 Jul 2023 13:38:25 +0000 (15:38 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
README.md
src/charging-station/Bootstrap.ts
src/charging-station/ChargingStationWorker.ts
src/charging-station/ui-server/AbstractUIServer.ts
src/charging-station/ui-server/UIHttpServer.ts
src/charging-station/ui-server/UIServerFactory.ts
src/types/ConfigurationData.ts
src/types/index.ts

index 69d46ccc3933d33235a6c6f09a617726032fa9a2..ae8eb0e7e7cd6e2a03c0ac1a8a3e90a2853cdf6e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -100,15 +100,15 @@ But the modifications to test have to be done to the files in the build target d
 
 **src/assets/config.json**:
 
-| Key                        | Value(s)                                     | Default Value                                                                                                                                                                                                                 | Value type                                                                                                                                                                                                                                                         | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
-| -------------------------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
-| supervisionUrls            |                                              | []                                                                                                                                                                                                                            | string \| string[]                                                                                                                                                                                                                                                 | string or strings array containing global connection URIs to OCPP-J servers                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
-| supervisionUrlDistribution | round-robin/random/charging-station-affinity | charging-station-affinity                                                                                                                                                                                                     | string                                                                                                                                                                                                                                                             | supervision urls distribution policy to simulated charging stations                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
-| log                        |                                              | {<br />"enabled": true,<br />"file": "logs/combined.log",<br />"errorFile": "logs/error.log",<br />"statisticsInterval": 60,<br />"level": "info",<br />"console": false,<br />"format": "simple",<br />"rotate": true<br />} | {<br />enabled: boolean;<br />file: string;<br />errorFile: string;<br />statisticsInterval: number;<br />level: string;<br />console: boolean;<br />format: string;<br />rotate: boolean;<br />maxFiles: string \| number;<br />maxSize: string \| number;<br />} | Log configuration section:<br />- _enabled_: enable logging<br />- _file_: log file relative path<br />- _errorFile_: error log file relative path<br />- _statisticsInterval_: seconds between charging stations statistics output in the logs<br />- _level_: emerg/alert/crit/error/warning/notice/info/debug [winston](https://github.com/winstonjs/winston) logging level</br >- _console_: output logs on the console<br />- _format_: [winston](https://github.com/winstonjs/winston) log format<br />- _rotate_: enable daily log files rotation<br />- _maxFiles_: maximum number of log files: https://github.com/winstonjs/winston-daily-rotate-file#options<br />- _maxSize_: maximum size of log files in bytes, or units of kb, mb, and gb: https://github.com/winstonjs/winston-daily-rotate-file#options |
-| worker                     |                                              | {<br />"processType": "workerSet",<br />"startDelay": 500,<br />"elementStartDelay": 0,<br />"elementsPerWorker": 'auto',<br />"poolMinSize": 4,<br />"poolMaxSize": 16<br />}                                                | {<br />processType: WorkerProcessType;<br />startDelay: number;<br />elementStartDelay: number;<br />elementsPerWorker: number \| 'auto';<br />poolMinSize: number;<br />poolMaxSize: number;<br />}                                                               | Worker configuration section:<br />- _processType_: worker threads process type (`workerSet`/`staticPool`/`dynamicPool`)<br />- _startDelay_: milliseconds to wait at worker threads startup (only for `workerSet` worker threads process type)<br />- _elementStartDelay_: milliseconds to wait at charging station startup<br />- _elementsPerWorker_: number of charging stations per worker threads for the `workerSet` process type (`auto` means (number of stations) / (number of CPUs) \* 1.5 if (number of stations) > (number of CPUs), otherwise 1)<br />- _poolMinSize_: worker threads pool minimum number of threads</br >- _poolMaxSize_: worker threads pool maximum number of threads                                                                                                                   |
-| uiServer                   |                                              | {<br />"enabled": false,<br />"type": "ws",<br />"options": {<br />"host": "localhost",<br />"port": 8080<br />}<br />}                                                                                                       | {<br />enabled: boolean;<br />type: ApplicationProtocol;<br />options: ServerOptions;<br />authentication: {<br />enabled: boolean;<br />type: AuthenticationType;<br />username: string;<br />password: string;<br />}<br />}                                     | UI server configuration section                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
-| performanceStorage         |                                              | {<br />"enabled": false,<br />"type": "jsonfile",<br />"file:///performanceRecords.json"<br />}                                                                                                                               | {<br />enabled: boolean;<br />type: string;<br />URI: string;<br />}<br />where type can be 'jsonfile' or 'mongodb'                                                                                                                                                | performance storage configuration section                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
-| stationTemplateUrls        |                                              | {}[]                                                                                                                                                                                                                          | {<br />file: string;<br />numberOfStations: number;<br />}[]                                                                                                                                                                                                       | array of charging station configuration templates URIs configuration section (charging station configuration template file name and number of stations)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
+| Key                        | Value(s)                                     | Default Value                                                                                                                                                                                                                 | Value type                                                                                                                                                                                                                                                               | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
+| -------------------------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| supervisionUrls            |                                              | []                                                                                                                                                                                                                            | string \| string[]                                                                                                                                                                                                                                                       | string or strings array containing global connection URIs to OCPP-J servers                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
+| supervisionUrlDistribution | round-robin/random/charging-station-affinity | charging-station-affinity                                                                                                                                                                                                     | string                                                                                                                                                                                                                                                                   | supervision urls distribution policy to simulated charging stations                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
+| log                        |                                              | {<br />"enabled": true,<br />"file": "logs/combined.log",<br />"errorFile": "logs/error.log",<br />"statisticsInterval": 60,<br />"level": "info",<br />"console": false,<br />"format": "simple",<br />"rotate": true<br />} | {<br />enabled: boolean;<br />file: string;<br />errorFile: string;<br />statisticsInterval: number;<br />level: string;<br />console: boolean;<br />format: string;<br />rotate: boolean;<br />maxFiles: string \| number;<br />maxSize: string \| number;<br />}       | Log configuration section:<br />- _enabled_: enable logging<br />- _file_: log file relative path<br />- _errorFile_: error log file relative path<br />- _statisticsInterval_: seconds between charging stations statistics output in the logs<br />- _level_: emerg/alert/crit/error/warning/notice/info/debug [winston](https://github.com/winstonjs/winston) logging level</br >- _console_: output logs on the console<br />- _format_: [winston](https://github.com/winstonjs/winston) log format<br />- _rotate_: enable daily log files rotation<br />- _maxFiles_: maximum number of log files: https://github.com/winstonjs/winston-daily-rotate-file#options<br />- _maxSize_: maximum size of log files in bytes, or units of kb, mb, and gb: https://github.com/winstonjs/winston-daily-rotate-file#options |
+| worker                     |                                              | {<br />"processType": "workerSet",<br />"startDelay": 500,<br />"elementStartDelay": 0,<br />"elementsPerWorker": 'auto',<br />"poolMinSize": 4,<br />"poolMaxSize": 16<br />}                                                | {<br />processType: WorkerProcessType;<br />startDelay: number;<br />elementStartDelay: number;<br />elementsPerWorker: number \| 'auto';<br />poolMinSize: number;<br />poolMaxSize: number;<br />}                                                                     | Worker configuration section:<br />- _processType_: worker threads process type (`workerSet`/`staticPool`/`dynamicPool`)<br />- _startDelay_: milliseconds to wait at worker threads startup (only for `workerSet` worker threads process type)<br />- _elementStartDelay_: milliseconds to wait at charging station startup<br />- _elementsPerWorker_: number of charging stations per worker threads for the `workerSet` process type (`auto` means (number of stations) / (number of CPUs) \* 1.5 if (number of stations) > (number of CPUs), otherwise 1)<br />- _poolMinSize_: worker threads pool minimum number of threads</br >- _poolMaxSize_: worker threads pool maximum number of threads                                                                                                                   |
+| uiServer                   |                                              | {<br />"enabled": false,<br />"type": "ws",<br />"options": {<br />"host": "localhost",<br />"port": 8080<br />}<br />}                                                                                                       | {<br />enabled: boolean;<br />type: ApplicationProtocol;<br />version: ApplicationProtocolVersion;<br />options: ServerOptions;<br />authentication: {<br />enabled: boolean;<br />type: AuthenticationType;<br />username: string;<br />password: string;<br />}<br />} | UI server configuration sectio9n:<br />- _enabled_: enable UI server<br />- _type_: 'http' or 'ws'<br />- _version_: '1.1' or '2.0'<br />_options_: node.js net module [listen options](https://nodejs.org/api/net.html#serverlistenoptions-callback)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
+| performanceStorage         |                                              | {<br />"enabled": false,<br />"type": "jsonfile",<br />"file:///performanceRecords.json"<br />}                                                                                                                               | {<br />enabled: boolean;<br />type: string;<br />URI: string;<br />}<br />where type can be 'jsonfile' or 'mongodb'                                                                                                                                                      | performance storage configuration section                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
+| stationTemplateUrls        |                                              | {}[]                                                                                                                                                                                                                          | {<br />file: string;<br />numberOfStations: number;<br />}[]                                                                                                                                                                                                             | array of charging station configuration templates URIs configuration section (charging station configuration template file name and number of stations)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
 
 #### Worker process model
 
index 76b2c2999d00318960199be014bfab9a49b60150..7e23949ca8aca4f6dc0e93998b94bd9121634759 100644 (file)
@@ -109,7 +109,7 @@ export class Bootstrap extends EventEmitter {
 
   public async start(): Promise<void> {
     if (!isMainThread) {
-      throw new Error('Cannot start charging stations simulator from worker thread');
+      throw new BaseError('Cannot start charging stations simulator from worker thread');
     }
     if (this.started === false) {
       if (this.starting === false) {
@@ -176,7 +176,7 @@ export class Bootstrap extends EventEmitter {
 
   public async stop(): Promise<void> {
     if (!isMainThread) {
-      throw new Error('Cannot stop charging stations simulator from worker thread');
+      throw new BaseError('Cannot stop charging stations simulator from worker thread');
     }
     if (this.started === true) {
       if (this.stopping === false) {
index ff9dbe6286dab402ec6531ca03d05e4792e538e3..7c7a523558bd6e9b547afe8775ec71c79f11187b 100644 (file)
@@ -6,6 +6,7 @@ import { parentPort } from 'node:worker_threads';
 import { ThreadWorker } from 'poolifier';
 
 import { ChargingStation } from './ChargingStation';
+import { BaseError } from '../exception';
 import type { ChargingStationWorkerData } from '../types';
 import { Configuration } from '../utils';
 import { POOL_MAX_INACTIVE_TIME, type WorkerMessage, WorkerMessageEvents } from '../worker';
@@ -48,7 +49,7 @@ class ChargingStationWorker extends AsyncResource {
           }
           break;
         default:
-          throw new Error(
+          throw new BaseError(
             `Unknown worker event: '${message.event}' received with data: '${JSON.stringify(
               message.data,
               null,
index 5dbe5b20dab588c875f36459c4adba0dedb46d21..133389d60b3cf18e01ad04922332121bbf0d37da 100644 (file)
@@ -1,4 +1,5 @@
 import { type IncomingMessage, Server, type ServerResponse } from 'node:http';
+import { type Http2Server, createServer } from 'node:http2';
 
 import type { WebSocket } from 'ws';
 
@@ -6,6 +7,7 @@ import type { AbstractUIService } from './ui-services/AbstractUIService';
 import { UIServiceFactory } from './ui-services/UIServiceFactory';
 import { BaseError } from '../../exception';
 import {
+  ApplicationProtocolVersion,
   AuthenticationType,
   type ChargingStationData,
   type ProcedureName,
@@ -19,13 +21,24 @@ import {
 
 export abstract class AbstractUIServer {
   public readonly chargingStations: Map<string, ChargingStationData>;
-  protected readonly httpServer: Server;
+  protected readonly httpServer: Server | Http2Server;
   protected readonly responseHandlers: Map<string, ServerResponse | WebSocket>;
   protected readonly uiServices: Map<ProtocolVersion, AbstractUIService>;
 
   public constructor(protected readonly uiServerConfiguration: UIServerConfiguration) {
     this.chargingStations = new Map<string, ChargingStationData>();
-    this.httpServer = new Server();
+    switch (this.uiServerConfiguration.version) {
+      case ApplicationProtocolVersion.VERSION_11:
+        this.httpServer = new Server();
+        break;
+      case ApplicationProtocolVersion.VERSION_20:
+        this.httpServer = createServer();
+        break;
+      default:
+        throw new BaseError(
+          `Unsupported application protocol version ${this.uiServerConfiguration.version}`,
+        );
+    }
     this.responseHandlers = new Map<string, ServerResponse | WebSocket>();
     this.uiServices = new Map<ProtocolVersion, AbstractUIService>();
   }
index ee12b3f4de996ed3a8f86b2a4db97949e9ebaf4e..e11fd4bdc662e18597887dca4c5273578a6f6724 100644 (file)
@@ -6,6 +6,7 @@ import { AbstractUIServer } from './AbstractUIServer';
 import { UIServerUtils } from './UIServerUtils';
 import { BaseError } from '../../exception';
 import {
+  ApplicationProtocolVersion,
   type ProcedureName,
   type Protocol,
   type ProtocolRequest,
@@ -43,9 +44,12 @@ export class UIHttpServer extends AbstractUIServer {
     this.startHttpServer();
   }
 
-  // eslint-disable-next-line @typescript-eslint/no-unused-vars
   public sendRequest(request: ProtocolRequest): void {
-    // This is intentionally left blank
+    switch (this.uiServerConfiguration.version) {
+      case ApplicationProtocolVersion.VERSION_20:
+        this.httpServer.emit('request', request);
+        break;
+    }
   }
 
   public sendResponse(response: ProtocolResponse): void {
index c4006b0396d96c8d5ad50e902bfedf8ea2743c65..49f088377c514f1d90059436fa11aef6cb6695c0 100644 (file)
@@ -4,7 +4,12 @@ import type { AbstractUIServer } from './AbstractUIServer';
 import { UIHttpServer } from './UIHttpServer';
 import { UIServerUtils } from './UIServerUtils';
 import { UIWebSocketServer } from './UIWebSocketServer';
-import { ApplicationProtocol, type UIServerConfiguration } from '../../types';
+import {
+  ApplicationProtocol,
+  ApplicationProtocolVersion,
+  type UIServerConfiguration,
+} from '../../types';
+import { isUndefined } from '../../utils';
 
 export class UIServerFactory {
   private constructor() {
@@ -21,6 +26,13 @@ export class UIServerFactory {
         ),
       );
     }
+    uiServerConfiguration = {
+      ...(uiServerConfiguration.type === ApplicationProtocol.HTTP &&
+        isUndefined(uiServerConfiguration.version) && {
+          version: ApplicationProtocolVersion.VERSION_11,
+        }),
+      ...uiServerConfiguration,
+    };
     switch (uiServerConfiguration.type) {
       case ApplicationProtocol.WS:
         return new UIWebSocketServer(uiServerConfiguration);
index ebec3a0d81aa327f5831a8a80a8fd1e8444baa36..95d30bdc8024fbef1cd21e1c55e91212ca4464d1 100644 (file)
@@ -39,9 +39,15 @@ export interface LogConfiguration {
   maxSize?: string | number;
 }
 
+export enum ApplicationProtocolVersion {
+  VERSION_11 = 1.1,
+  VERSION_20 = 2.0,
+}
+
 export interface UIServerConfiguration {
   enabled?: boolean;
   type?: ApplicationProtocol;
+  version?: ApplicationProtocolVersion;
   options?: ServerOptions;
   authentication?: {
     enabled: boolean;
index 04608aaba3289fc9910c246b2bfdf1a9d21383a4..11f1138ce69a895aafe5a77d42dc6e384a005d2c 100644 (file)
@@ -164,6 +164,7 @@ export {
   type WsOptions,
 } from './ChargingStationTemplate';
 export {
+  ApplicationProtocolVersion,
   type ConfigurationData,
   ConfigurationSection,
   type LogConfiguration,