import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { readFileSync } from 'fs'; import * as yaml from 'js-yaml'; import { Model } from 'mongoose'; import { join } from 'path'; import { SemanticVersionDto } from 'src/versioning/dto/semanticversion.dto'; import { VersioningService } from '../versioning/versioning.service'; import { LoggingService } from 'src/logging/logging.service'; import { PerformanceDocument } from './models/performance.model'; const COMPONENT_NAME = 'performance'; enum UpdateReturnCodes { Updated, Ignored, Failure, } @Injectable() export class PerformanceService { private static readPerformanceFile(): Record { return yaml.load( readFileSync(join(process.cwd(), 'config/performance.yaml'), 'utf8'), ) as Record; } private async updatePerformanceData( performanceData: Record, version: SemanticVersionDto, ): Promise { return this.performanceModel.deleteMany({}).then(async () => { const invalidEntries: string[] = []; for (const key in performanceData) { if (key !== 'FILEINFO') { const validAircraft = performanceData[key]['speedabovefl240'] !== undefined && performanceData[key]['rodabovefl240'] !== undefined && performanceData[key]['speedabovefl100'] !== undefined && performanceData[key]['rodabovefl100'] !== undefined && performanceData[key]['speedbelowfl100'] !== undefined && performanceData[key]['rodbelowfl100'] !== undefined && performanceData[key]['speedapproach'] !== undefined; if (!validAircraft) { invalidEntries.push(key); } else { await this.performanceModel.create({ icaoCode: key, aboveFL240: { speed: performanceData[key]['speedabovefl240'], rateOfDescend: performanceData[key]['rodabovefl240'], }, aboveFL100: { speed: performanceData[key]['speedabovefl100'], rateOfDescend: performanceData[key]['rodabovefl100'], }, belowFL100: { speed: performanceData[key]['speedbelowfl100'], rateOfDescend: performanceData[key]['rodbelowfl100'], }, minimalApproachSpeed: performanceData[key]['speedapproach'], }); } } } await this.versioningService.updateComponent( COMPONENT_NAME, performanceData['FILEINFO']['createdAt'], version, ); return invalidEntries; }); } private async validateAndUpdatePerformanceData(): Promise<{ status: UpdateReturnCodes; ignored: string[]; }> { // read the performance file and validate the version length const data = PerformanceService.readPerformanceFile(); if (data['FILEINFO'] === undefined) { this.loggingService.addInfoMessage( COMPONENT_NAME, `The fileinfo block is missing`, ); return { status: UpdateReturnCodes.Failure, ignored: [] }; } if (data['FILEINFO']['createdAt'] === undefined) { this.loggingService.addInfoMessage( COMPONENT_NAME, `The createdAt of the fileinfo block is missing`, ); return { status: UpdateReturnCodes.Failure, ignored: [] }; } const versionParts = (data['FILEINFO']['version'] as string).split('.'); if (versionParts.length !== 3) { this.loggingService.addInfoMessage( COMPONENT_NAME, `The version of fileinfo is missing or wrong: ${data['FILEINFO']['version']}. Expected: x.y.z`, ); return { status: UpdateReturnCodes.Failure, ignored: [] }; } // create the fileversion const fileversion: SemanticVersionDto = { main: parseInt(versionParts[0]), major: parseInt(versionParts[1]), minor: parseInt(versionParts[2]), }; return this.versioningService .findComponent(COMPONENT_NAME) .then(async (resp) => { if ( resp === null || VersioningService.newerVersion( { main: resp.versionMain, major: resp.versionMajor, minor: resp.versionMinor, }, fileversion, ) ) { return { status: UpdateReturnCodes.Updated, ignored: await this.updatePerformanceData(data, fileversion), }; } return { status: UpdateReturnCodes.Ignored, ignored: [] }; }) .catch(async () => ({ status: UpdateReturnCodes.Updated, ignored: await this.updatePerformanceData(data, fileversion), })); } constructor( @InjectModel('performance') private readonly performanceModel: Model, private readonly versioningService: VersioningService, private readonly loggingService: LoggingService, ) { this.validateAndUpdatePerformanceData().then(async (response) => { response.ignored.forEach(async (entry) => { await this.loggingService.addInfoMessage( COMPONENT_NAME, `Ignored ${entry}. Required entries: speedabovefl240, rodabovefl240, speedabovefl100, rodabovefl100, speedbelowfl100, rodbelowfl100, speedapproach`, ); }); if (response.status === UpdateReturnCodes.Ignored) { await this.loggingService.addInfoMessage( COMPONENT_NAME, `Ignored the performance file due to the file version`, ); } else if (response.status === UpdateReturnCodes.Failure) { await this.loggingService.addInfoMessage( COMPONENT_NAME, `Wasn't able to update the performance database`, ); } }); } }