diff --git a/api/server.js b/api/server.js index 0b7490c..78522f1 100644 --- a/api/server.js +++ b/api/server.js @@ -16,6 +16,12 @@ const cors = require('cors'); const mongoose = require('mongoose'); const {exec} = require('child_process'); +// cluster mode +const cluster = require('cluster'); +const envWorkerNum = process.env.NODE_WORKER_COUNT; +const cpuCount = require('os').cpus().length; +const numWorkers = (envWorkerNum && envWorkerNum < cpuCount) ? envWorkerNum : cpuCount; + // own modules const config = require('./config/config'); const urls = require('./config/api-url'); @@ -108,7 +114,7 @@ if (process.env.NODE_ENV === config.test.unit.env || process.env.NODE_ENV === co const mongoServer = new MongodbMemoryServer(); mongoose.Promise = Promise; mongoServer.getConnectionString().then((mongoUri) => { - mongoose.connect(mongoUri); + mongoose.connect(mongoUri, {useNewUrlParser: true}); mongoose.connection.on('error', (e) => { if (e.message.code === 'ETIMEDOUT') { @@ -139,17 +145,29 @@ if (process.env.NODE_ENV === config.test.unit.env || process.env.NODE_ENV === co }); }); } else { - const mongoosePromise = mongoose.connect(config.database.uri + config.database.db); - mongoosePromise.then((db) => { - app.listen(config.port, (err) => { - if (err !== undefined) { - error('Error on startup, ', err); - } else { - logger('Listening on port ' + config.port); - signatureCronJob.start(); - backupCronJob.start(); + mongoose.connect(config.database.uri + config.database.db, {useNewUrlParser: true}).then((db) => { + if (cluster.isMaster) { + // Fork workers + for (let i = 0; i < numWorkers; i++) { + cluster.fork(); } - }); + logger(`Master ${process.pid} is running. Forking ${numWorkers} workers`); + + // Check if worker id is died + cluster.on('exit', (worker, code, signal) => { + logger(`worker ${worker.process.pid} died`); + }); + } else { + app.listen(config.port, (err) => { + if (err !== undefined) { + error(`Error on startup ${err}`); + } else { + logger(`Worker ${process.pid} started. Listening on port ${config.port}`); + signatureCronJob.start(); + backupCronJob.start(); + } + }); + } }); } diff --git a/api/tools/log-parse-tool.js b/api/tools/log-parse-tool.js index c58b410..83a72c0 100644 --- a/api/tools/log-parse-tool.js +++ b/api/tools/log-parse-tool.js @@ -42,10 +42,10 @@ const parseWarLog = (lineArray, war) => { const VEHICLE_BLACKLIST = [ 'Prowler (Unbewaffnet)', 'Prowler (Bewaffnet)', 'Hunter', - 'HEMTT Transporter', 'HEMTT Transporter (abgedeckt)', 'HEMTT SanitÀtsfahrzeug', + 'HEMTT Transporter', 'HEMTT Transporter (abgedeckt)', 'HEMTT Sanitätsfahrzeug', 'Remote Designator [NATO]', 'UGV Stomper', 'Qilin (Unbewaffnet)', 'Qilin (Bewaffnet)', 'Ifrit', - 'Tempest-Transporter', 'Tempest-Transporter (abgedeckt)', 'Tempest SanitÀtsfahrzeug', + 'Tempest-Transporter', 'Tempest-Transporter (abgedeckt)', 'Tempest Sanitätsfahrzeug', 'Remote Designator [CSAT]', 'UBF Saif', 'Quad Bike', 'HuntIR', ]; @@ -108,19 +108,28 @@ const parseWarLog = (lineArray, war) => { const kill = { war: war._id, time: getFullTimeDate(war.date, line.split(WHITESPACE)[5]), - shooter: shooter ? shooter.name : null, - target: target ? target.name : null, - friendlyFire: shooter ? target.fraction === shooter.fraction : false, - fraction: shooter ? shooter.fraction : 'NONE', }; - if (shooter.magazine) { - kill.magazine = shooter.magazine; + if (shooter) { + kill.shooter = shooter.name; + kill.fraction = shooter.fraction; + if (target) { + kill.friendlyFire = (target.fraction === shooter.fraction); + } + if (shooter.magazine) { + kill.magazine = shooter.magazine; + } + if (shooter.vehicle) { + kill.shooterVehicle = shooter.vehicle; + } + } else { + kill.fraction = 'NONE'; } - if (shooter.vehicle) { - kill.shooterVehicle = shooter.vehicle; - } - if (target.vehicle) { - kill.targetVehicle = target.vehicle; + + if (target) { + kill.target = target.name; + if (target.vehicle) { + kill.targetVehicle = target.vehicle; + } } stats.kills.push(kill); } @@ -312,12 +321,15 @@ const getPlayerInfoFromString = (inputString) => { let name; if (playerNameRegexMatch && playerNameRegexMatch.length >= 2) { name = playerNameRegexMatch[2].trim(); - // do not return player for 'Error: No unit' - if (!name && name === 'Error: No unit') { + // do not return player for 'unbekannt' or 'Error: No unit' + if (!name || name === 'unbekannt' || name === 'Error: No unit' || name === 'Selbstverschulden.') { return; } resPlayer.name = name; + } else { + return; } + // ADDITIONAL PLAYER NAMES let additionalPlayerMatch; while ((additionalPlayerMatch = playerNameRegex.exec(inputString)) !== null) { @@ -341,7 +353,7 @@ const getPlayerInfoFromString = (inputString) => { } if (side && side !== 'ENEMY') { - resPlayer.fraction = side === 'WEST' ? 'BLUFOR' : 'OPFOR'; + resPlayer.fraction = (side === 'WEST') ? 'BLUFOR' : 'OPFOR'; } // MAGAZINE diff --git a/package.json b/package.json index 212fa65..2adfecd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opt-cc", - "version": "1.8.1", + "version": "1.8.2", "author": "Florian Hartwich ", "private": true, "scripts": { diff --git a/static/package-lock.json b/static/package-lock.json index aefdb1e..94f3c66 100644 --- a/static/package-lock.json +++ b/static/package-lock.json @@ -4219,11 +4219,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4236,15 +4238,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -4347,7 +4352,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -4357,6 +4363,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4369,17 +4376,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -4396,6 +4406,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -4468,7 +4479,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -4478,6 +4490,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -4583,6 +4596,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", diff --git a/static/src/app/pub/decoration-overview/decoration-overview.component.ts b/static/src/app/pub/decoration-overview/decoration-overview.component.ts index 82996ec..b2de28d 100644 --- a/static/src/app/pub/decoration-overview/decoration-overview.component.ts +++ b/static/src/app/pub/decoration-overview/decoration-overview.component.ts @@ -1,4 +1,4 @@ -import {Component, OnInit} from '@angular/core'; +import {Component, OnDestroy, OnInit} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {Fraction} from '../../utils/fraction.enum'; @@ -14,7 +14,7 @@ import {Location} from '@angular/common'; templateUrl: './decoration-overview.component.html', styleUrls: ['./decoration-overview.component.css'] }) -export class DecorationOverviewComponent implements OnInit { +export class DecorationOverviewComponent implements OnInit, OnDestroy { decorations: Decoration[]; @@ -54,6 +54,10 @@ export class DecorationOverviewComponent implements OnInit { }); }; + ngOnDestroy() { + this.bottomSheet.dismiss(); + } + switchFraction(value: any) { this.medals = this.decorations.filter(d => d.fraction === value && d.isMedal); this.ribbons = this.decorations.filter(d => d.fraction === value && !d.isMedal); diff --git a/static/src/app/pub/rank-overview/rank-overview.component.ts b/static/src/app/pub/rank-overview/rank-overview.component.ts index 293cd2d..f4931b3 100644 --- a/static/src/app/pub/rank-overview/rank-overview.component.ts +++ b/static/src/app/pub/rank-overview/rank-overview.component.ts @@ -1,4 +1,4 @@ -import {Component, OnInit} from '@angular/core'; +import {Component, OnDestroy, OnInit} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {Fraction} from '../../utils/fraction.enum'; import {Rank} from '../../models/model-interfaces'; @@ -12,7 +12,7 @@ import {UserListSheetComponent} from '../user-list-sheet/user-list-sheet.compone templateUrl: './rank-overview.component.html', styleUrls: ['./rank-overview.component.css'] }) -export class RankOverviewComponent implements OnInit { +export class RankOverviewComponent implements OnInit, OnDestroy { ranksOpfor: Rank[]; @@ -37,6 +37,10 @@ export class RankOverviewComponent implements OnInit { }); }; + ngOnDestroy() { + this.bottomSheet.dismiss(); + } + selectRow(rank: Rank) { this.bottomSheet.open(UserListSheetComponent, {data: {rank: rank}}); } diff --git a/static/src/app/statistic/campaign/campaign-navigation/campaign-navigation.component.css b/static/src/app/statistic/campaign/campaign-navigation/campaign-navigation.component.css index 0696913..affab38 100644 --- a/static/src/app/statistic/campaign/campaign-navigation/campaign-navigation.component.css +++ b/static/src/app/statistic/campaign/campaign-navigation/campaign-navigation.component.css @@ -7,7 +7,7 @@ .scroll-btn-right { top: 50px; - left: calc(100vw - 45px); + left: calc(100vw - 50px); } .scroll-btn mat-icon { diff --git a/static/src/app/statistic/campaign/campaign-navigation/campaign-navigation.component.ts b/static/src/app/statistic/campaign/campaign-navigation/campaign-navigation.component.ts index 8b2eed2..07f6a65 100644 --- a/static/src/app/statistic/campaign/campaign-navigation/campaign-navigation.component.ts +++ b/static/src/app/statistic/campaign/campaign-navigation/campaign-navigation.component.ts @@ -1,4 +1,14 @@ -import {Component, ElementRef, EventEmitter, Input, OnChanges, Output, ViewChild} from '@angular/core'; +import { + AfterViewInit, + Component, + ElementRef, + EventEmitter, + Input, + OnChanges, + Output, + SimpleChanges, + ViewChild +} from '@angular/core'; import {Campaign} from '../../../models/model-interfaces'; import {LoginService} from '../../../services/app-user-service/login-service'; @@ -30,8 +40,10 @@ export class CampaignNavigationComponent implements OnChanges { constructor(public loginService: LoginService) { } - ngOnChanges() { - this.isRightScrollVisible = this.campaigns.length > 4; + ngOnChanges(changes: SimpleChanges) { + if (!changes.selectedCampaignId) { + this.isRightScrollVisible = this.campaigns.length > 4; + } } select(campaign) {