First refactoring
MODIFY
src/server/ocpp/json/JsonCentralSystemServer.ts
src/server/ocpp/json/JsonCentralSystemServer.ts
@@ -23,8 +23,6 @@ export default class JsonCentralSystemServer extends CentralSystemServer {
private wsServer: WSServer;
private jsonChargingStationClients: Map<string, JsonWSConnection>;
private jsonRestClients: Map<string, JsonRestWSConnection>;
- private keepAliveIntervalValue: number;
- private keepAliveInterval: NodeJS.Timeout;
constructor(centralSystemConfig: CentralSystemConfiguration, chargingStationConfig: ChargingStationConfiguration) {
// Call parent
@@ -32,7 +30,6 @@ export default class JsonCentralSystemServer extends CentralSystemServer {
// Keep local
this.jsonChargingStationClients = new Map<string, JsonWSConnection>();
this.jsonRestClients = new Map<string, JsonRestWSConnection>();
- this.keepAliveIntervalValue = (this.centralSystemConfig.keepaliveinterval ? this.centralSystemConfig.keepaliveinterval : Constants.WS_DEFAULT_KEEPALIVE) * 1000; // Milliseconds
}
public start(): void {
@@ -43,17 +40,8 @@ export default class JsonCentralSystemServer extends CentralSystemServer {
}
public getChargingStationClient(tenantID: string, chargingStationID: string): ChargingStationClient {
- // Build ID
- const id = `${tenantID}~${chargingStationID}`;
// Get the Json Web Socket
- let jsonWebSocket: JsonWSConnection;
- const jsonChargingStationClientsReversedMap = new Map<string, JsonWSConnection>(Array.from(this.jsonChargingStationClients).reverse());
- for (const [wsClientID, wsClient] of jsonChargingStationClientsReversedMap) {
- if (wsClientID.startsWith(id) && wsClient.isWSConnectionOpen()) {
- jsonWebSocket = wsClient;
- break;
- }
- }
+ const jsonWebSocket = this.jsonChargingStationClients.get(`${tenantID}~${chargingStationID}`);
if (!jsonWebSocket) {
void Logging.logError({
tenantID: tenantID,
@@ -164,29 +152,9 @@ export default class JsonCentralSystemServer extends CentralSystemServer {
}
} catch (error) {
await Logging.logException(error, ServerAction.WS_CONNECTION, '', MODULE_NAME, 'connection', Constants.DEFAULT_TENANT);
- // Respond
ws.close(WebSocketCloseEventStatusCode.CLOSE_UNSUPPORTED, error.message);
}
});
- // Keep alive WebSocket connection
- if (this.keepAliveIntervalValue > 0 && !this.keepAliveInterval) {
- this.keepAliveInterval = setInterval((): void => {
- for (const jsonWSConnection of this.jsonChargingStationClients.values()) {
- if (!jsonWSConnection.isConnectionAlive) {
- void Logging.logError({
- tenantID: jsonWSConnection.getTenantID(),
- source: jsonWSConnection.getChargingStationID(),
- action: ServerAction.WS_JSON_CONNECTION_CLOSED,
- module: MODULE_NAME, method: 'createWSServer',
- message: `WebSocket does not respond to ping (IP: ${jsonWSConnection.getClientIP().toString()}), terminating`
- });
- jsonWSConnection.getWSConnection().terminate();
- }
- jsonWSConnection.isConnectionAlive = false;
- jsonWSConnection.getWSConnection().ping((): void => { });
- }
- }, this.keepAliveIntervalValue);
- }
}
}

MODIFY
src/server/ocpp/json/JsonWSConnection.ts
src/server/ocpp/json/JsonWSConnection.ts
@@ -21,7 +21,6 @@ import http from 'http';
const MODULE_NAME = 'JsonWSConnection';
export default class JsonWSConnection extends WSConnection {
- public isConnectionAlive: boolean;
private chargingStationClient: ChargingStationClient;
private chargingStationService: JsonChargingStationService;
private headers: OCPPHeader;
@@ -49,7 +48,6 @@ export default class JsonWSConnection extends WSConnection {
message: `Protocol ${wsConnection.protocol} not supported`
});
}
- this.isConnectionAlive = true;
// Handle Socket ping
this.getWSConnection().on('ping', this.onPing.bind(this));
// Handle Socket pong
@@ -73,9 +71,7 @@ export default class JsonWSConnection extends WSConnection {
Address: this.getClientIP()
}
};
- // Ok
this.initialized = true;
- // Log
await Logging.logInfo({
tenantID: this.getTenantID(),
source: this.getChargingStationID(),
@@ -87,10 +83,9 @@ export default class JsonWSConnection extends WSConnection {
}
public onError(errorEvent: ErrorEvent): void {
- // Log
void Logging.logError({
tenantID: this.getTenantID(),
- source: this.getChargingStationID() ? this.getChargingStationID() : '',
+ source: this.getChargingStationID(),
action: ServerAction.WS_JSON_CONNECTION_ERROR,
module: MODULE_NAME, method: 'onError',
message: `Error ${errorEvent?.error} ${errorEvent?.message}`,
@@ -99,30 +94,39 @@ export default class JsonWSConnection extends WSConnection {
}
public onClose(closeEvent: CloseEvent): void {
- // Log
void Logging.logInfo({
tenantID: this.getTenantID(),
- source: this.getChargingStationID() ? this.getChargingStationID() : '',
+ source: this.getChargingStationID(),
action: ServerAction.WS_JSON_CONNECTION_CLOSED,
module: MODULE_NAME, method: 'onClose',
message: `Connection has been closed, Reason: '${closeEvent.reason ? closeEvent.reason : 'No reason given'}', Message: '${Utils.getWebSocketCloseEventStatusString(Utils.convertToInt(closeEvent))}', Code: '${closeEvent.toString()}'`,
detailedMessages: { closeEvent: closeEvent }
});
- // Remove the connection
- this.wsServer.removeJsonConnection(this);
}
public async onPing(): Promise<void> {
+ void Logging.logDebug({
+ tenantID: this.getTenantID(),
+ source: this.getChargingStationID(),
+ action: ServerAction.WS_JSON_CONNECTION_PINGED,
+ module: MODULE_NAME, method: 'onPing',
+ message: 'Ping received',
+ });
await this.updateChargingStationLastSeen();
}
public async onPong(): Promise<void> {
- this.isConnectionAlive = true;
+ void Logging.logDebug({
+ tenantID: this.getTenantID(),
+ source: this.getChargingStationID(),
+ action: ServerAction.WS_JSON_CONNECTION_PONGED,
+ module: MODULE_NAME, method: 'onPong',
+ message: 'Pong received',
+ });
await this.updateChargingStationLastSeen();
}
public async handleRequest(messageId: string, commandName: ServerAction, commandPayload: Record<string, unknown> | string): Promise<void> {
- // Log
await Logging.logChargingStationServerReceiveAction(MODULE_NAME, this.getTenantID(), this.getChargingStationID(), commandName, commandPayload);
const methodName = `handle${commandName}`;
// Check if method exist in the service
@@ -149,10 +153,7 @@ export default class JsonWSConnection extends WSConnection {
}
public getChargingStationClient(): ChargingStationClient {
- // Only return client if WS is open
- if (this.isWSConnectionOpen()) {
- return this.chargingStationClient;
- }
+ if (!this.isWSConnectionOpen()) {
void Logging.logError({
tenantID: this.getTenantID(),
source: this.getChargingStationID(),
@@ -162,6 +163,8 @@ export default class JsonWSConnection extends WSConnection {
});
return null;
}
+ return this.chargingStationClient;
+ }
private async updateChargingStationLastSeen(): Promise<void> {
// Update once every 60s

MODIFY
src/server/ocpp/json/WSConnection.ts
src/server/ocpp/json/WSConnection.ts
@@ -21,7 +21,6 @@ const MODULE_NAME = 'WSConnection';
export default abstract class WSConnection {
protected initialized: boolean;
protected wsServer: JsonCentralSystemServer;
- private readonly uuid: string;
private readonly chargingStationID: string;
private readonly tenantID: string;
private readonly token: string;
@@ -76,7 +75,6 @@ export default abstract class WSConnection {
message: `The URL '${req.url}' is invalid (/(OCPPxx|REST)/TENANT_ID/CHARGEBOX_ID)`
});
}
- this.uuid = Utils.generateUUID();
let logMsg = `Unknown type WS connection attempts with URL: '${req.url}'`;
let action: ServerAction = ServerAction.WS_CONNECTION_OPENED;
if (req.url.startsWith('/REST')) {
@@ -343,12 +341,10 @@ export default abstract class WSConnection {
}
public getTenantID(): string {
- // Check
if (this.isTenantValid()) {
- // Ok
return this.tenantID;
}
- // No, go to the master tenant
+ // No: go to the master tenant
return Constants.DEFAULT_TENANT;
}
@@ -357,7 +353,7 @@ export default abstract class WSConnection {
}
public getID(): string {
- return `${this.getTenantID()}~${this.getChargingStationID()}~${this.uuid}`;
+ return `${this.getTenantID()}~${this.getChargingStationID()}`;
}
public isTenantValid(): boolean {

MODIFY
src/types/Server.ts
src/types/Server.ts
@@ -236,6 +236,8 @@ export enum ServerAction {
WS_JSON_CONNECTION_OPENED = 'WSJsonConnectionOpened',
WS_JSON_CONNECTION_CLOSED = 'WSJsonConnectionClosed',
WS_JSON_CONNECTION_ERROR = 'WSJsonConnectionError',
+ WS_JSON_CONNECTION_PINGED = 'WSJsonConnectionPinged',
+ WS_JSON_CONNECTION_PONGED = 'WSJsonConnectionPonged',
WS_REST_CONNECTION_OPENED = 'WSRestServerConnectionOpened',
WS_REST_CONNECTION_CLOSED = 'WSRestServerConnectionClosed',

MODIFY
src/utils/Constants.ts
src/utils/Constants.ts
@@ -282,7 +282,6 @@ export default class Constants {
public static readonly ANONYMIZED_VALUE = '####';
- public static readonly WS_DEFAULT_KEEPALIVE = 180; // Seconds
public static readonly WS_RECONNECT_DISABLED = 0;
public static readonly WS_RECONNECT_UNLIMITED = -1;
public static readonly WS_DEFAULT_RECONNECT_MAX_RETRIES = -1;

First refactoring