Enhanced Json Server
MODIFY
src/server/ocpp/json/JsonCentralSystemServer.ts
src/server/ocpp/json/JsonCentralSystemServer.ts
@@ -582,7 +582,7 @@ export default class JsonCentralSystemServer extends CentralSystemServer {
});
}
} else {
- this.isDebug() && Logging.logConsoleDebug('No Web Socket connection to ping');
+ this.isDebug() && Logging.logConsoleDebug(`No ${type} Web Socket connection to ping`);
}
}
}

MODIFY
src/server/ocpp/json/JsonWSConnection.ts
src/server/ocpp/json/JsonWSConnection.ts
@@ -128,8 +128,9 @@ export default class JsonWSConnection extends WSConnection {
}
private async updateChargingStationLastSeen(): Promise<void> {
- // Update once every 60s
- if (!this.lastSeen || (Date.now() - this.lastSeen.getTime()) > Constants.LAST_SEEN_UPDATE_INTERVAL_MILLIS) {
+ // Update once every ping interval / 2
+ if (!this.lastSeen ||
+ (Date.now() - this.lastSeen.getTime()) > (Configuration.getChargingStationConfig().pingIntervalOCPPJSecs * 1000 / 2)) {
// Update last seen
this.lastSeen = new Date();
const chargingStation = await ChargingStationStorage.getChargingStation(this.getTenant(),

MODIFY
src/storage/mongodb/DatabaseUtils.ts
src/storage/mongodb/DatabaseUtils.ts
@@ -426,8 +426,8 @@ export default class DatabaseUtils {
{ $eq: ['$firmwareUpdateStatus', OCPPFirmwareStatus.INSTALLING] },
{
$gte: [
- { $divide: [{ $subtract: [new Date(), '$lastSeen'] }, 1000] },
- Configuration.getChargingStationConfig().pingIntervalOCPPJSecs * 2
+ { $subtract: [new Date(), '$lastSeen'] },
+ Configuration.getChargingStationConfig().pingIntervalOCPPJSecs * 2 * 1000
]
}
]

MODIFY
src/storage/mongodb/LoggingStorage.ts
src/storage/mongodb/LoggingStorage.ts
@@ -5,6 +5,7 @@ import Constants from '../../utils/Constants';
import DatabaseUtils from './DatabaseUtils';
import DbParams from '../../types/database/DbParams';
import { Log } from '../../types/Log';
+import { ServerType } from '../../types/Server';
import Tenant from '../../types/Tenant';
import Utils from '../../utils/Utils';
@@ -37,7 +38,7 @@ export default class LoggingStorage {
companyID: DatabaseUtils.convertToObjectID(logToSave.companyID),
siteID: DatabaseUtils.convertToObjectID(logToSave.siteID),
siteAreaID: DatabaseUtils.convertToObjectID(logToSave.siteAreaID),
- source: logToSave.source,
+ source: global.serverType ?? ServerType.CENTRAL_SERVER,
host: logToSave.host ? logToSave.host : Utils.getHostName(),
timestamp: Utils.convertToDate(logToSave.timestamp),
module: logToSave.module,

MODIFY
src/types/Log.ts
src/types/Log.ts
@@ -5,7 +5,7 @@ import User from './User';
import UserToken from './UserToken';
export interface Log extends AuthorizationActions {
- tenantID: string;
+ tenantID?: string;
id?: string;
level?: LogLevel;
chargingStationID?: string;

MODIFY
src/types/Server.ts
src/types/Server.ts
@@ -91,6 +91,8 @@ export enum ServerAction {
OFFLINE_CHARGING_STATION = 'OfflineChargingStation',
+ MISSING_CONFIGURATION = 'MissingConfiguration',
+
LOGS_CLEANUP = 'LogsCleanup',
PERFORMANCES_CLEANUP = 'PerformancesCleanup',
PERFORMANCES = 'Performances',

MODIFY
src/utils/Configuration.ts
src/utils/Configuration.ts
@@ -15,7 +15,9 @@ import EmailConfiguration from '../types/configuration/EmailConfiguration';
import FirebaseConfiguration from '../types/configuration/FirebaseConfiguration';
import HealthCheckConfiguration from '../types/configuration/HealthCheckConfiguration';
import JsonEndpointConfiguration from '../types/configuration/JsonEndpointConfiguration';
+import { LogLevel } from '../types/Log';
import LoggingConfiguration from '../types/configuration/LoggingConfiguration';
+import LoggingStorage from '../storage/mongodb/LoggingStorage';
import MigrationConfiguration from '../types/configuration/MigrationConfiguration';
import NotificationConfiguration from '../types/configuration/NotificationConfiguration';
import OCPIEndpointConfiguration from '../types/configuration/OCPIEndpointConfiguration';
@@ -24,11 +26,15 @@ import ODataServiceConfiguration from '../types/configuration/ODataServiceConfig
import OICPEndpointConfiguration from '../types/configuration/OICPEndpointConfiguration';
import OICPServiceConfiguration from '../types/configuration/OICPServiceConfiguration';
import SchedulerConfiguration from '../types/configuration/SchedulerConfiguration';
+import { ServerAction } from '../types/Server';
import StorageConfiguration from '../types/configuration/StorageConfiguration';
import WSDLEndpointConfiguration from '../types/configuration/WSDLEndpointConfiguration';
+import chalk from 'chalk';
import fs from 'fs';
import global from './../types/GlobalType';
+const MODULE_NAME = 'Configuration';
+
export default class Configuration {
private static config: ConfigurationData;
@@ -108,7 +114,7 @@ export default class Configuration {
}
public static getEmailConfig(): EmailConfiguration {
- if (Configuration.isUndefined(Configuration.getConfig().Email.disableBackup)) {
+ if (Configuration.isUndefined('Email.disableBackup', Configuration.getConfig().Email.disableBackup)) {
Configuration.getConfig().Email.disableBackup = false;
}
return Configuration.getConfig().Email;
@@ -125,14 +131,14 @@ export default class Configuration {
public static getChargingStationConfig(): ChargingStationConfiguration {
// Read conf and set defaults values
const chargingStationConfiguration: ChargingStationConfiguration = Configuration.getConfig().ChargingStation;
- if (!Configuration.isUndefined(chargingStationConfiguration)) {
- if (Configuration.isUndefined(chargingStationConfiguration.heartbeatIntervalOCPPSSecs)) {
+ if (!Configuration.isUndefined('ChargingStation', chargingStationConfiguration)) {
+ if (Configuration.isUndefined('ChargingStation.heartbeatIntervalOCPPSSecs', chargingStationConfiguration.heartbeatIntervalOCPPSSecs)) {
chargingStationConfiguration.heartbeatIntervalOCPPSSecs = 60;
}
- if (Configuration.isUndefined(chargingStationConfiguration.heartbeatIntervalOCPPJSecs)) {
- chargingStationConfiguration.heartbeatIntervalOCPPJSecs = 120;
+ if (Configuration.isUndefined('ChargingStation.heartbeatIntervalOCPPJSecs', chargingStationConfiguration.heartbeatIntervalOCPPJSecs)) {
+ chargingStationConfiguration.heartbeatIntervalOCPPJSecs = 3600;
}
- if (Configuration.isUndefined(chargingStationConfiguration.pingIntervalOCPPJSecs)) {
+ if (Configuration.isUndefined('ChargingStation.pingIntervalOCPPJSecs', chargingStationConfiguration.pingIntervalOCPPJSecs)) {
chargingStationConfiguration.pingIntervalOCPPJSecs = 60;
}
}
@@ -144,43 +150,43 @@ export default class Configuration {
}
public static getHealthCheckConfig(): HealthCheckConfiguration {
- if (Configuration.isUndefined(Configuration.getConfig().HealthCheck)) {
+ if (Configuration.isUndefined('HealthCheck', Configuration.getConfig().HealthCheck)) {
Configuration.getConfig().HealthCheck = {} as HealthCheckConfiguration;
}
- if (Configuration.isUndefined(Configuration.getConfig().HealthCheck.enabled)) {
+ if (Configuration.isUndefined('HealthCheck.enabled', Configuration.getConfig().HealthCheck.enabled)) {
Configuration.getConfig().HealthCheck.enabled = true;
}
return Configuration.getConfig().HealthCheck;
}
public static getMigrationConfig(): MigrationConfiguration {
- if (Configuration.isUndefined(Configuration.getConfig().Migration)) {
+ if (Configuration.isUndefined('Migration', Configuration.getConfig().Migration)) {
Configuration.getConfig().Migration = {} as MigrationConfiguration;
}
- if (Configuration.isUndefined(Configuration.getConfig().Migration.active)) {
+ if (Configuration.isUndefined('Migration.active', Configuration.getConfig().Migration.active)) {
Configuration.getConfig().Migration.active = false;
}
return Configuration.getConfig().Migration;
}
public static getChargingStationTemplatesConfig(): ChargingStationTemplatesConfiguration {
- if (Configuration.isUndefined(Configuration.getConfig().ChargingStationTemplates)) {
+ if (Configuration.isUndefined('ChargingStationTemplates', Configuration.getConfig().ChargingStationTemplates)) {
Configuration.getConfig().ChargingStationTemplates = {} as ChargingStationTemplatesConfiguration;
}
- if (Configuration.isUndefined(Configuration.getConfig().ChargingStationTemplates.templatesFilePath)) {
+ if (Configuration.isUndefined('ChargingStationTemplates.templatesFilePath', Configuration.getConfig().ChargingStationTemplates.templatesFilePath)) {
Configuration.getConfig().ChargingStationTemplates.templatesFilePath = `${global.appRoot}/assets/charging-station-templates/charging-stations.json`;
}
return Configuration.getConfig().ChargingStationTemplates;
}
public static getAxiosConfig(): AxiosConfiguration {
- if (Configuration.isUndefined(Configuration.getConfig().Axios)) {
+ if (Configuration.isUndefined('Axios', Configuration.getConfig().Axios)) {
Configuration.getConfig().Axios = {} as AxiosConfiguration;
}
- if (Configuration.isUndefined(Configuration.getConfig().Axios.timeout)) {
+ if (Configuration.isUndefined('Axios.timeout', Configuration.getConfig().Axios.timeout)) {
Configuration.getConfig().Axios.timeout = Constants.AXIOS_DEFAULT_TIMEOUT;
}
- if (Configuration.isUndefined(Configuration.getConfig().Axios.retries)) {
+ if (Configuration.isUndefined('Axios.retries', Configuration.getConfig().Axios.retries)) {
Configuration.getConfig().Axios.retries = 0;
}
return Configuration.getConfig().Axios;
@@ -194,8 +200,18 @@ export default class Configuration {
}
// Dup method: Avoid circular deps with Utils class
- private static isUndefined(obj: any): boolean {
- return typeof obj === 'undefined';
+ private static isUndefined(name: string, value: any): boolean {
+ if (typeof value === 'undefined') {
+ console.error(chalk.red(`Missing property '${name}' in config.json`));
+ void LoggingStorage.saveLog(Constants.DEFAULT_TENANT, {
+ level: LogLevel.WARNING,
+ timestamp: new Date(),
+ module: MODULE_NAME, method: 'propertyIsUndefined',
+ action: ServerAction.MISSING_CONFIGURATION,
+ message: `Missing property '${name}' in config.json`
+ });
+ return true;
+ }
+ return false;
}
}
-

MODIFY
src/utils/Logging.ts
src/utils/Logging.ts
@@ -99,25 +99,25 @@ export default class Logging {
public static async logDebug(log: Log): Promise<string> {
log.level = LogLevel.DEBUG;
// eslint-disable-next-line @typescript-eslint/no-floating-promises
- return Logging._log(log);
+ return Logging.log(log);
}
public static async logInfo(log: Log): Promise<string> {
log.level = LogLevel.INFO;
// eslint-disable-next-line @typescript-eslint/no-floating-promises
- return Logging._log(log);
+ return Logging.log(log);
}
public static async logWarning(log: Log): Promise<string> {
log.level = LogLevel.WARNING;
// eslint-disable-next-line @typescript-eslint/no-floating-promises
- return Logging._log(log);
+ return Logging.log(log);
}
public static async logError(log: Log): Promise<string> {
log.level = LogLevel.ERROR;
// eslint-disable-next-line @typescript-eslint/no-floating-promises
- return Logging._log(log);
+ return Logging.log(log);
}
public static logConsoleError(message: string): void {
@@ -540,13 +540,14 @@ export default class Logging {
public static async logException(exception: Error, action: ServerAction,
module: string, method: string, tenantID: string, user?: UserToken | User | string): Promise<void> {
if (exception instanceof AppAuthError) {
- await Logging._logActionAppAuthExceptionMessage(tenantID, action, exception);
+ await Logging.logActionAppAuthException(tenantID, action, exception);
} else if (exception instanceof AppError) {
- await Logging._logActionAppExceptionMessage(tenantID, action, exception);
+ await Logging.logActionAppException(tenantID, action, exception);
} else if (exception instanceof BackendError) {
- await Logging._logActionBackendExceptionMessage(tenantID, action, exception);
+ await Logging.logActionBackendException(tenantID, action, exception);
} else {
- await Logging.logError(Logging._buildLog(exception, action, module, method, tenantID, user));
+ await Logging.logError(
+ Logging.buildLogError(action, module, method, tenantID, user, exception));
}
}
@@ -554,15 +555,15 @@ export default class Logging {
public static async logActionExceptionMessage(tenantID: string, action: ServerAction, exception: Error, detailedMessages = {}): Promise<void> {
// Log App Error
if (exception instanceof AppError) {
- await Logging._logActionAppExceptionMessage(tenantID, action, exception, detailedMessages);
+ await Logging.logActionAppException(tenantID, action, exception, detailedMessages);
// Log Backend Error
} else if (exception instanceof BackendError) {
- await Logging._logActionBackendExceptionMessage(tenantID, action, exception, detailedMessages);
+ await Logging.logActionBackendException(tenantID, action, exception, detailedMessages);
// Log Auth Error
} else if (exception instanceof AppAuthError) {
- await Logging._logActionAppAuthExceptionMessage(tenantID, action, exception, detailedMessages);
+ await Logging.logActionAppAuthException(tenantID, action, exception, detailedMessages);
} else {
- await Logging._logActionExceptionMessage(tenantID, action, exception, detailedMessages);
+ await Logging.logActionException(tenantID, action, exception, detailedMessages);
}
}
@@ -579,18 +580,18 @@ export default class Logging {
let statusCode;
// Log App Error
if (exception instanceof AppError) {
- await Logging._logActionAppExceptionMessage(tenantID, action, exception);
+ await Logging.logActionAppException(tenantID, action, exception);
statusCode = exception.params.errorCode;
// Log Backend Error
} else if (exception instanceof BackendError) {
- await Logging._logActionBackendExceptionMessage(tenantID, action, exception);
+ await Logging.logActionBackendException(tenantID, action, exception);
statusCode = HTTPError.GENERAL_ERROR;
// Log Auth Error
} else if (exception instanceof AppAuthError) {
- await Logging._logActionAppAuthExceptionMessage(tenantID, action, exception);
+ await Logging.logActionAppAuthException(tenantID, action, exception);
statusCode = exception.params.errorCode;
} else {
- await Logging._logActionExceptionMessage(tenantID, action, exception);
+ await Logging.logActionException(tenantID, action, exception);
}
// Send error
res.status(statusCode ? statusCode : HTTPError.GENERAL_ERROR).send({
@@ -688,7 +689,7 @@ export default class Logging {
}
}
- private static async _logActionExceptionMessage(tenantID: string, action: ServerAction, exception: any, detailedMessages = {}): Promise<void> {
+ private static async logActionException(tenantID: string, action: ServerAction, exception: any, detailedMessages = {}): Promise<void> {
await Logging.logError({
tenantID: tenantID,
user: exception.user,
@@ -700,7 +701,7 @@ export default class Logging {
});
}
- private static async _logActionAppExceptionMessage(tenantID: string, action: ServerAction, exception: AppError, detailedMessages = {}): Promise<void> {
+ private static async logActionAppException(tenantID: string, action: ServerAction, exception: AppError, detailedMessages = {}): Promise<void> {
// Add Exception stack
if (exception.params.detailedMessages) {
exception.params.detailedMessages = {
@@ -728,7 +729,7 @@ export default class Logging {
});
}
- private static async _logActionBackendExceptionMessage(tenantID: string, action: ServerAction, exception: BackendError, detailedMessages = {}): Promise<void> {
+ private static async logActionBackendException(tenantID: string, action: ServerAction, exception: BackendError, detailedMessages = {}): Promise<void> {
// Add Exception stack
if (exception.params.detailedMessages) {
exception.params.detailedMessages = {
@@ -757,7 +758,7 @@ export default class Logging {
}
// Used to check URL params (not in catch)
- private static async _logActionAppAuthExceptionMessage(tenantID: string, action: ServerAction, exception: AppAuthError, detailedMessages = {}): Promise<void> {
+ private static async logActionAppAuthException(tenantID: string, action: ServerAction, exception: AppAuthError, detailedMessages = {}): Promise<void> {
await Logging.logError({
tenantID: tenantID,
user: exception.params.user,
@@ -777,39 +778,8 @@ export default class Logging {
});
}
- private static _buildLog(error, action: ServerAction, module: string,
- method: string, tenantID: string, user: UserToken | User | string): Log {
- const tenant = tenantID ? tenantID : Constants.DEFAULT_TENANT;
- if (error.params) {
- return {
- user: user,
- tenantID: tenant,
- actionOnUser: error.params.actionOnUser,
- module: module, method: method,
- action: action,
- message: error.message,
- detailedMessages: {
- details: error.params.detailedMessages,
- error: error.stack
- }
- };
- }
- return {
- user: user,
- tenantID: tenant,
- actionOnUser: error.actionOnUser,
- module: module, method: method,
- action: action,
- message: error.message,
- detailedMessages: {
- details: error.detailedMessages,
- stack: error.stack
- }
- };
- }
-
// Used to check URL params (not in catch)
- private static _format(detailedMessage: any): string {
+ private static format(detailedMessage: any): string {
// JSON?
if (typeof detailedMessage === 'object') {
try {
@@ -821,7 +791,7 @@ export default class Logging {
}
}
- private static async _log(log: Log): Promise<string> {
+ private static async log(log: Log): Promise<string> {
let moduleConfig = null;
// Check Log Level
const loggingConfig = Logging.getConfiguration();
@@ -884,7 +854,7 @@ export default class Logging {
log.detailedMessages = [log.detailedMessages];
}
// Format
- log.detailedMessages = Logging._format(log.detailedMessages);
+ log.detailedMessages = Logging.format(log.detailedMessages);
}
// First char always in Uppercase
if (typeof log.message === 'string' && log.message && log.message.length > 0) {
@@ -893,8 +863,7 @@ export default class Logging {
if (!log.tenantID || log.tenantID === '') {
log.tenantID = Constants.DEFAULT_TENANT;
}
- // Source
- log.source = global.serverType ?? ServerType.CENTRAL_SERVER;
+ // Save
return LoggingStorage.saveLog(log.tenantID, log);
}
@@ -972,4 +941,35 @@ export default class Logging {
});
return null;
}
+
+ private static buildLogError(action: ServerAction, module: string,
+ method: string, tenantID: string, user: UserToken | User | string, error: any): Log {
+ const tenant = tenantID ? tenantID : Constants.DEFAULT_TENANT;
+ if (error.params) {
+ return {
+ user: user,
+ tenantID: tenant,
+ actionOnUser: error.params.actionOnUser,
+ module: module, method: method,
+ action: action,
+ message: error.message,
+ detailedMessages: {
+ details: error.params.detailedMessages,
+ error: error.stack
+ }
+ };
+ }
+ return {
+ user: user,
+ tenantID: tenant,
+ actionOnUser: error.actionOnUser,
+ module: module, method: method,
+ action: action,
+ message: error.message,
+ detailedMessages: {
+ details: error.detailedMessages,
+ stack: error.stack
+ }
+ };
+ }
}

Enhanced Json Server