fix: various fixes to files handling and their content caching
[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,
14 type ProtocolVersion,
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,
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
a307349b
JB
49 protected startHttpServer(): void {
50 if (this.httpServer.listening === false) {
51 this.httpServer.listen(this.uiServerConfiguration.options);
52 }
53 }
54
143498c8
JB
55 protected registerProtocolVersionUIService(version: ProtocolVersion): void {
56 if (this.uiServices.has(version) === false) {
57 this.uiServices.set(version, UIServiceFactory.getUIServiceImplementation(version, this));
58 }
59 }
60
976d11ec
JB
61 protected authenticate(req: IncomingMessage, next: (err?: Error) => void): void {
62 if (this.isBasicAuthEnabled() === true) {
63 if (this.isValidBasicAuth(req) === false) {
7b5dbe91 64 next(new BaseError('Unauthorized'));
976d11ec
JB
65 }
66 next();
67 }
68 next();
69 }
70
71 private isBasicAuthEnabled(): boolean {
eb3abc4f
JB
72 return (
73 this.uiServerConfiguration.authentication?.enabled === true &&
74 this.uiServerConfiguration.authentication?.type === AuthenticationType.BASIC_AUTH
75 );
76 }
77
976d11ec 78 private isValidBasicAuth(req: IncomingMessage): boolean {
eb3abc4f
JB
79 const authorizationHeader = req.headers.authorization ?? '';
80 const authorizationToken = authorizationHeader.split(/\s+/).pop() ?? '';
81 const authentication = Buffer.from(authorizationToken, 'base64').toString();
82 const authenticationParts = authentication.split(/:/);
83 const username = authenticationParts.shift();
84 const password = authenticationParts.join(':');
85 return (
86 this.uiServerConfiguration.authentication?.username === username &&
87 this.uiServerConfiguration.authentication?.password === password
88 );
89 }
90
fe94fce0 91 public abstract start(): void;
5e3cb728
JB
92 public abstract sendRequest(request: ProtocolRequest): void;
93 public abstract sendResponse(response: ProtocolResponse): void;
94 public abstract logPrefix(
95 moduleName?: string,
96 methodName?: string,
97 prefixSuffix?: string
98 ): string;
fe94fce0 99}