build(deps-dev): apply updates
[e-mobility-charging-stations-simulator.git] / src / charging-station / ui-server / AbstractUIServer.ts
CommitLineData
01f4001e 1import { type IncomingMessage, Server, type ServerResponse } from 'node:http';
daa6505e
JB
2
3import type { WebSocket } from 'ws';
fe94fce0 4
4c3c0d59
JB
5import type { AbstractUIService } from './ui-services/AbstractUIService';
6import { UIServiceFactory } from './ui-services/UIServiceFactory';
7b5dbe91 7import { BaseError } from '../../exception';
eb3abc4f
JB
8import {
9 AuthenticationType,
268a74bb 10 type ChargingStationData,
e0b0ee21
JB
11 type ProcedureName,
12 type ProtocolRequest,
13 type ProtocolResponse,
f130b8e6 14 ProtocolVersion,
e0b0ee21
JB
15 type RequestPayload,
16 type ResponsePayload,
268a74bb
JB
17 type UIServerConfiguration,
18} from '../../types';
8114d10e 19
fe94fce0 20export abstract class AbstractUIServer {
32de5a57 21 public readonly chargingStations: Map<string, ChargingStationData>;
976d11ec
JB
22 protected readonly httpServer: Server;
23 protected readonly responseHandlers: Map<string, ServerResponse | WebSocket>;
5e3cb728 24 protected readonly uiServices: Map<ProtocolVersion, AbstractUIService>;
fe94fce0 25
eb3abc4f 26 public constructor(protected readonly uiServerConfiguration: UIServerConfiguration) {
32de5a57 27 this.chargingStations = new Map<string, ChargingStationData>();
daa6505e 28 this.httpServer = new Server();
94dc3080 29 this.responseHandlers = new Map<string, ServerResponse | WebSocket>();
fe94fce0
JB
30 this.uiServices = new Map<ProtocolVersion, AbstractUIService>();
31 }
32
852a4c5f
JB
33 public buildProtocolRequest(
34 id: string,
35 procedureName: ProcedureName,
5edd8ba0 36 requestPayload: RequestPayload,
5e3cb728
JB
37 ): ProtocolRequest {
38 return [id, procedureName, requestPayload];
852a4c5f
JB
39 }
40
5e3cb728
JB
41 public buildProtocolResponse(id: string, responsePayload: ResponsePayload): ProtocolResponse {
42 return [id, responsePayload];
852a4c5f
JB
43 }
44
daa6505e
JB
45 public stop(): void {
46 this.chargingStations.clear();
47 }
48
7c1395ab 49 public async sendInternalRequest(request: ProtocolRequest): Promise<ProtocolResponse> {
f130b8e6
JB
50 const protocolVersion = ProtocolVersion['0.0.1'];
51 this.registerProtocolVersionUIService(protocolVersion);
e1d9a0f4
JB
52 return this.uiServices
53 .get(protocolVersion)
54 ?.requestHandler(request) as Promise<ProtocolResponse>;
6bd808fd
JB
55 }
56
e64c6fa9
JB
57 public hasResponseHandler(id: string): boolean {
58 return this.responseHandlers.has(id);
1ca4a038
JB
59 }
60
a307349b
JB
61 protected startHttpServer(): void {
62 if (this.httpServer.listening === false) {
63 this.httpServer.listen(this.uiServerConfiguration.options);
64 }
65 }
66
143498c8
JB
67 protected registerProtocolVersionUIService(version: ProtocolVersion): void {
68 if (this.uiServices.has(version) === false) {
69 this.uiServices.set(version, UIServiceFactory.getUIServiceImplementation(version, this));
70 }
71 }
72
976d11ec
JB
73 protected authenticate(req: IncomingMessage, next: (err?: Error) => void): void {
74 if (this.isBasicAuthEnabled() === true) {
75 if (this.isValidBasicAuth(req) === false) {
7b5dbe91 76 next(new BaseError('Unauthorized'));
976d11ec
JB
77 }
78 next();
79 }
80 next();
81 }
82
83 private isBasicAuthEnabled(): boolean {
eb3abc4f
JB
84 return (
85 this.uiServerConfiguration.authentication?.enabled === true &&
86 this.uiServerConfiguration.authentication?.type === AuthenticationType.BASIC_AUTH
87 );
88 }
89
976d11ec 90 private isValidBasicAuth(req: IncomingMessage): boolean {
eb3abc4f
JB
91 const authorizationHeader = req.headers.authorization ?? '';
92 const authorizationToken = authorizationHeader.split(/\s+/).pop() ?? '';
93 const authentication = Buffer.from(authorizationToken, 'base64').toString();
94 const authenticationParts = authentication.split(/:/);
95 const username = authenticationParts.shift();
96 const password = authenticationParts.join(':');
97 return (
98 this.uiServerConfiguration.authentication?.username === username &&
99 this.uiServerConfiguration.authentication?.password === password
100 );
101 }
102
fe94fce0 103 public abstract start(): void;
5e3cb728
JB
104 public abstract sendRequest(request: ProtocolRequest): void;
105 public abstract sendResponse(response: ProtocolResponse): void;
106 public abstract logPrefix(
107 moduleName?: string,
108 methodName?: string,
5edd8ba0 109 prefixSuffix?: string,
5e3cb728 110 ): string;
fe94fce0 111}