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