build(deps-dev): apply updates
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / OCPPRequestService.ts
index c8d4c2fa9a7554ee653c5360ecab95909566c4d5..076dfb2166e3d38ca4bbe4c0ba67cd727c1bc514 100644 (file)
@@ -93,8 +93,6 @@ export abstract class OCPPRequestService {
       messagePayload: JsonType | OCPPError,
       messageType: MessageType,
       commandName: RequestCommand | IncomingRequestCommand,
-      responseCallback: ResponseCallback,
-      errorCallback: ErrorCallback,
     ) => string;
     this.validateRequestPayload = this.validateRequestPayload.bind(this) as <T extends JsonType>(
       chargingStation: ChargingStation,
@@ -381,69 +379,89 @@ export abstract class OCPPRequestService {
           messagePayload,
           messageType,
           commandName,
-          responseCallback,
-          errorCallback,
         );
-        let sendError = false;
         // Check if wsConnection opened
-        const wsOpened = chargingStation.isWebSocketConnectionOpened() === true;
-        if (wsOpened) {
+        if (chargingStation.isWebSocketConnectionOpened() === true) {
           const beginId = PerformanceStatistics.beginMeasure(commandName);
-          try {
-            setTimeout(() => {
-              return errorCallback(
-                new OCPPError(
-                  ErrorType.GENERIC_ERROR,
-                  `Timeout for message id '${messageId}'`,
-                  commandName,
-                  (messagePayload as JsonObject)?.details ?? Constants.EMPTY_FROZEN_OBJECT,
-                ),
-                false,
-              );
-            }, OCPPConstants.OCPP_WEBSOCKET_TIMEOUT);
-            chargingStation.wsConnection?.send(messageToSend);
-            logger.debug(
-              `${chargingStation.logPrefix()} >> Command '${commandName}' sent ${OCPPServiceUtils.getMessageTypeString(
-                messageType,
-              )} payload: ${messageToSend}`,
+          const sendTimeout = setTimeout(() => {
+            return errorCallback(
+              new OCPPError(
+                ErrorType.GENERIC_ERROR,
+                `Timeout for message id '${messageId}'`,
+                commandName,
+                (messagePayload as JsonObject)?.details ?? Constants.EMPTY_FROZEN_OBJECT,
+              ),
+              false,
             );
-          } catch (error) {
-            logger.error(
-              `${chargingStation.logPrefix()} >> Command '${commandName}' failed to send ${OCPPServiceUtils.getMessageTypeString(
-                messageType,
-              )} payload: ${messageToSend}:`,
-              error,
+          }, OCPPConstants.OCPP_WEBSOCKET_TIMEOUT);
+          chargingStation.wsConnection?.send(messageToSend, (error?: Error) => {
+            clearTimeout(sendTimeout);
+            if (error) {
+              const ocppError = new OCPPError(
+                ErrorType.GENERIC_ERROR,
+                `WebSocket errored for ${
+                  params?.skipBufferingOnError === false ? '' : 'non '
+                }buffered message id '${messageId}' with content '${messageToSend}'`,
+                commandName,
+                { name: error.name, message: error.message, stack: error.stack } ??
+                  Constants.EMPTY_FROZEN_OBJECT,
+              );
+              if (params?.skipBufferingOnError === false) {
+                // Buffer
+                chargingStation.bufferMessage(messageToSend);
+                // Reject and keep request in the cache
+                return reject(ocppError);
+              }
+              // Reject response
+              if (messageType !== MessageType.CALL_MESSAGE) {
+                return reject(ocppError);
+              }
+              // Reject and remove request from the cache
+              return errorCallback(ocppError, false);
+            }
+          });
+          if (messageType === MessageType.CALL_MESSAGE) {
+            this.cacheRequestPromise(
+              chargingStation,
+              messageId,
+              messagePayload as JsonType,
+              commandName,
+              responseCallback,
+              errorCallback,
             );
-            sendError = true;
           }
+          logger.debug(
+            `${chargingStation.logPrefix()} >> Command '${commandName}' sent ${OCPPServiceUtils.getMessageTypeString(
+              messageType,
+            )} payload: ${messageToSend}`,
+          );
           PerformanceStatistics.endMeasure(commandName, beginId);
-        }
-        const wsClosedOrErrored = !wsOpened || sendError === true;
-        if (wsClosedOrErrored && params?.skipBufferingOnError === false) {
-          // Buffer
-          chargingStation.bufferMessage(messageToSend);
+        } else {
+          if (params?.skipBufferingOnError === false) {
+            // Buffer
+            chargingStation.bufferMessage(messageToSend);
+            if (messageType === MessageType.CALL_MESSAGE) {
+              this.cacheRequestPromise(
+                chargingStation,
+                messageId,
+                messagePayload as JsonType,
+                commandName,
+                responseCallback,
+                errorCallback,
+              );
+            }
+          }
           // Reject and keep request in the cache
           return reject(
             new OCPPError(
               ErrorType.GENERIC_ERROR,
-              `WebSocket closed or errored for buffered message id '${messageId}' with content '${messageToSend}'`,
+              `WebSocket closed for ${
+                params?.skipBufferingOnError === false ? '' : 'non '
+              }buffered message id '${messageId}' with content '${messageToSend}'`,
               commandName,
               (messagePayload as JsonObject)?.details ?? Constants.EMPTY_FROZEN_OBJECT,
             ),
           );
-        } else if (wsClosedOrErrored) {
-          const ocppError = new OCPPError(
-            ErrorType.GENERIC_ERROR,
-            `WebSocket closed or errored for non buffered message id '${messageId}' with content '${messageToSend}'`,
-            commandName,
-            (messagePayload as JsonObject)?.details ?? Constants.EMPTY_FROZEN_OBJECT,
-          );
-          // Reject response
-          if (messageType !== MessageType.CALL_MESSAGE) {
-            return reject(ocppError);
-          }
-          // Reject and remove request from the cache
-          return errorCallback(ocppError, false);
         }
         // Resolve response
         if (messageType !== MessageType.CALL_MESSAGE) {
@@ -464,8 +482,6 @@ export abstract class OCPPRequestService {
     messagePayload: JsonType | OCPPError,
     messageType: MessageType,
     commandName: RequestCommand | IncomingRequestCommand,
-    responseCallback: ResponseCallback,
-    errorCallback: ErrorCallback,
   ): string {
     let messageToSend: string;
     // Type of message
@@ -474,12 +490,6 @@ export abstract class OCPPRequestService {
       case MessageType.CALL_MESSAGE:
         // Build request
         this.validateRequestPayload(chargingStation, commandName, messagePayload as JsonType);
-        chargingStation.requests.set(messageId, [
-          responseCallback,
-          errorCallback,
-          commandName,
-          messagePayload as JsonType,
-        ]);
         messageToSend = JSON.stringify([
           messageType,
           messageId,
@@ -512,6 +522,22 @@ export abstract class OCPPRequestService {
     return messageToSend;
   }
 
+  private cacheRequestPromise(
+    chargingStation: ChargingStation,
+    messageId: string,
+    messagePayload: JsonType,
+    commandName: RequestCommand | IncomingRequestCommand,
+    responseCallback: ResponseCallback,
+    errorCallback: ErrorCallback,
+  ): void {
+    chargingStation.requests.set(messageId, [
+      responseCallback,
+      errorCallback,
+      commandName,
+      messagePayload,
+    ]);
+  }
+
   // eslint-disable-next-line @typescript-eslint/no-unused-vars
   public abstract requestHandler<ReqType extends JsonType, ResType extends JsonType>(
     chargingStation: ChargingStation,