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