From f1449e50477b39cf050c9a27824feca75c1d7acc Mon Sep 17 00:00:00 2001 From: Florian Hartwich Date: Fri, 20 Oct 2017 23:42:41 +0200 Subject: [PATCH 01/19] Add parser for basic events --- api/cron-job/cron.js | 2 +- api/middleware/util.js | 14 ++ api/routes/command.js | 2 +- api/routes/wars.js | 62 +------- .../backplate/blufor.png | Bin .../backplate/opfor.png | Bin .../font/DEJAVU_SANS_13.fnt | 0 .../font/DEJAVU_SANS_13.png | Bin .../font/DEVAJU_SANS_19.fnt | 0 .../font/DEVAJU_SANS_19.png | Bin api/tools/log-parse-tool.js | 146 ++++++++++++++++++ .../signature-tool.js | 0 static/src/app/app.component.ts | 4 +- 13 files changed, 171 insertions(+), 59 deletions(-) rename api/{signature-tool => tools}/backplate/blufor.png (100%) rename api/{signature-tool => tools}/backplate/opfor.png (100%) rename api/{signature-tool => tools}/font/DEJAVU_SANS_13.fnt (100%) rename api/{signature-tool => tools}/font/DEJAVU_SANS_13.png (100%) rename api/{signature-tool => tools}/font/DEVAJU_SANS_19.fnt (100%) rename api/{signature-tool => tools}/font/DEVAJU_SANS_19.png (100%) create mode 100644 api/tools/log-parse-tool.js rename api/{signature-tool => tools}/signature-tool.js (100%) diff --git a/api/cron-job/cron.js b/api/cron-job/cron.js index b9c1790..a0ca8b3 100644 --- a/api/cron-job/cron.js +++ b/api/cron-job/cron.js @@ -4,7 +4,7 @@ const cron = require('cron'); const async = require('async'); const {exec} = require('child_process'); const UserModel = require('../models/user'); -const signatureTool = require('../signature-tool/signature-tool'); +const signatureTool = require('../tools/signature-tool'); const createAllSignatures = () => { console.log('\x1b[35m%s\x1b[0m', new Date().toLocaleString() diff --git a/api/middleware/util.js b/api/middleware/util.js index 1ab04d2..233b5b0 100644 --- a/api/middleware/util.js +++ b/api/middleware/util.js @@ -11,4 +11,18 @@ const sortCollectionBy = (collection, key) => { return collection; }; +const arrayContains = (arr, user) => { + let i = 0, count = arr.length, matchFound = false; + + for(; i < count; i++) { + if (arr[i] === user) { + matchFound = true; + break; + } + } + + return matchFound; +}; + exports.sortCollection = sortCollectionBy; +exports.arrayContains = arrayContains; diff --git a/api/routes/command.js b/api/routes/command.js index 5759d07..4439bbe 100644 --- a/api/routes/command.js +++ b/api/routes/command.js @@ -9,7 +9,7 @@ const codes = require('./http-codes'); const routerHandling = require('../middleware/router-handling'); const createAllSignatures = require('../cron-job/cron').createAllSignatures; -const createSignature = require('../signature-tool/signature-tool'); +const createSignature = require('../tools/signature-tool'); const command = express.Router(); diff --git a/api/routes/wars.js b/api/routes/wars.js index a3000ad..33866b2 100644 --- a/api/routes/wars.js +++ b/api/routes/wars.js @@ -17,6 +17,8 @@ const apiAuthenticationMiddleware = require('../middleware/auth-middleware'); const checkMT = require('../middleware/permission-check').checkMT; const routerHandling = require('../middleware/router-handling'); +const parseWarLog = require('../tools/log-parse-tool'); + // Mongoose Model using mongoDB const CampaignModel = require('../models/campaign'); const WarModel = require('../models/war'); @@ -62,69 +64,19 @@ wars.route('/') .post(apiAuthenticationMiddleware, checkMT, upload.single('log'), (req, res, next) => { let body = req.body; - let parts = body.date.split("-"); - body.date = new Date(parseInt(parts[0], 10), - parseInt(parts[1], 10) - 1, - parseInt(parts[2], 10)); const war = new WarModel(body); if (req.file) { - war.save((err, war) => { - if (err) { - return next(err); - } - const folderName = __dirname + '/../resource/logs/' + war._id; - mkdirp(folderName, function (err) { + fs.readFile(req.file.buffer, (file, err) => { if (err) { return next(err); } - fs.appendFile(folderName + '/war.log', new Buffer(req.file.buffer), (err) => { - if (err) { - return next(err); - } - exec(__dirname + '/../war-parser/run.sh ' + folderName + ' ' + war._id, (error, stdout) => { - if (error) { - return next(error); - } - exec(__dirname + '/../war-parser/clean.sh /../' + folderName + ' | tee ' + folderName + '/clean.log', (error) => { - if (error) { - return next(error); - } - let obj = JSON.parse(`${stdout}`); - for (let i = 0; i < obj.length; i++) { - if (!obj[i].fraction) { - obj.splice(i, 1); - } else if (obj[i].fraction === 'BLUFOR') { - war.playersBlufor++; - } else { - war.playersOpfor++; - } - } + const lineArray = file.toString().split("\n"); + parseWarLog(lineArray, {}); - WarModel.findByIdAndUpdate(war._id, war, {new: true}, (err, item) => { - if (err) { - err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("item not found"); - err.status = codes.notfound; - } - else { - PlayerModel.create(obj, function (err) { - if (err) { - return next(err); - } - res.status(codes.created); - res.locals.items = war; - return next(); - }); - } - }) - }); - }); - }); }); - }) + res.locals.processed = true; + return next(); } else { const err = new Error('no Logfile provided'); diff --git a/api/signature-tool/backplate/blufor.png b/api/tools/backplate/blufor.png similarity index 100% rename from api/signature-tool/backplate/blufor.png rename to api/tools/backplate/blufor.png diff --git a/api/signature-tool/backplate/opfor.png b/api/tools/backplate/opfor.png similarity index 100% rename from api/signature-tool/backplate/opfor.png rename to api/tools/backplate/opfor.png diff --git a/api/signature-tool/font/DEJAVU_SANS_13.fnt b/api/tools/font/DEJAVU_SANS_13.fnt similarity index 100% rename from api/signature-tool/font/DEJAVU_SANS_13.fnt rename to api/tools/font/DEJAVU_SANS_13.fnt diff --git a/api/signature-tool/font/DEJAVU_SANS_13.png b/api/tools/font/DEJAVU_SANS_13.png similarity index 100% rename from api/signature-tool/font/DEJAVU_SANS_13.png rename to api/tools/font/DEJAVU_SANS_13.png diff --git a/api/signature-tool/font/DEVAJU_SANS_19.fnt b/api/tools/font/DEVAJU_SANS_19.fnt similarity index 100% rename from api/signature-tool/font/DEVAJU_SANS_19.fnt rename to api/tools/font/DEVAJU_SANS_19.fnt diff --git a/api/signature-tool/font/DEVAJU_SANS_19.png b/api/tools/font/DEVAJU_SANS_19.png similarity index 100% rename from api/signature-tool/font/DEVAJU_SANS_19.png rename to api/tools/font/DEVAJU_SANS_19.png diff --git a/api/tools/log-parse-tool.js b/api/tools/log-parse-tool.js new file mode 100644 index 0000000..192ce94 --- /dev/null +++ b/api/tools/log-parse-tool.js @@ -0,0 +1,146 @@ +"use strict"; + +const arrayContains = require('../middleware/util').arrayContains; + +const parseWarLog = (lineArray, war) => { + const clean = []; + const budget = []; + const points = []; + const kills = []; + const respawn = []; + const revive = []; + const flag = []; + const transport = []; + const playerNames = []; + + const addPlayerIfNotExists = (playerName) => { + if (playerName !== 'Error: No unit' && !arrayContains(playerNames, playerName)) { + playerNames.push(playerName); + } + }; + + lineArray.forEach(line => { + if (line.includes("Abschuss")) { + clean.push(line); + // const kill = line.split(" "); + // for (let i=0; i< kill.length; i++ ) { + // console.log(i + " +++ " + kill[i]); + // } + + } + + if (line.includes("Budget")) { + clean.push(line); + const budg = line.split(" "); + if (line.includes("Endbudget")) { + war["endBudgetBlufor"] = transformMoneyString(budg[11]); + war['endBudgetOpfor'] = transformMoneyString(budg[14]); + } else if (line.includes("Startbudget")) { + war["budgetBlufor"] = transformMoneyString(budg[11]); + war["budgetOpfor"] = transformMoneyString(budg[14]); + } else { + budget.push(getBudgetEntry(budg)); + } + } + + if (line.includes("Fahne")) { + clean.push(line); + + } + + if (line.includes("Punkte")) { + clean.push(line); + const pt = line.split(" "); + + if (line.includes("Endpunktestand")) { + war['ptBlufor'] = parseInt(pt[11]); + war['ptOpfor'] = parseInt(pt[14].slice(0, -1)); + } else { + points.push(getPointsEntry(pt)) + } + } + + if (line.includes("Respawn")) { + clean.push(line); + const resp = line.split(" "); + const playerName = line.substring(line.lastIndexOf("Spieler:") + 9, line.lastIndexOf("-") - 1); + + respawn.push(getRespawnEntry(resp, playerName)); + addPlayerIfNotExists(playerName); + } + + if (line.includes("Revive")) { + clean.push(line); + //console.log(line); + } + + if (line.includes("Transport ||")) { + clean.push(line); + const driverName = line.substring(line.lastIndexOf("wurde von ") + 10, line.lastIndexOf(" eingeflogen")); + const driverNameArray = driverName.split(" "); + const driverFraction = driverNameArray[driverNameArray.length-1] === "(WEST)" ? "BLUFOR" : "OPFOR"; + const sanitizedDriverName = driverName.substring(0, driverName.indexOf(driverNameArray[driverNameArray.length-1])-1); + + const passengerName = line.substring(line.lastIndexOf("|| ") + 3, line.lastIndexOf(" wurde von")); + const passengerNameArray = passengerName.split(" "); + const passengerFraction = passengerNameArray[passengerNameArray.length-1] === "(WEST)" ? "BLUFOR" : "OPFOR"; + const sanitizedPassengerName = passengerName.substring(0, passengerName.indexOf(passengerNameArray[passengerNameArray.length-1])-1); + const distance = parseInt(line.substring(line.lastIndexOf("eingeflogen (") + 13, line.lastIndexOf("m)") - 1)); + + transport.push({ + war: "blablub7z8", + driver: sanitizedDriverName, + passenger: sanitizedPassengerName, + distance: distance + }); + + addPlayerIfNotExists(sanitizedDriverName); + addPlayerIfNotExists(sanitizedPassengerName); + } + }); + // + playerNames.forEach(budg => console.log(budg)); +}; + +function getRespawnEntry(respawn, playerName) { + return { + war: "1234567", + time: getDateTime(respawn[5]), + player: playerName + } +} + +function getPointsEntry(pt) { + return { + warId: "123-xyz-123", + time: getDateTime(pt[5]), + ptBlufor: parseInt(pt[12]), + ptOpfor: parseInt(pt[15].slice(0, -1)) + } +} + +function getBudgetEntry(budg) { + return { + warId: "123-xyz-123", + time: getDateTime(budg[5]), + fraction: budg[9] === "NATO" ? "BLUFOR" : "OPFOR", + oldBudget: transformMoneyString(budg[11]), + newBudget: transformMoneyString(budg[14]) + } +} + +const transformMoneyString = (budgetString) => { + if (!budgetString.includes("e+")) { + return parseInt(budgetString); + } + const budget = budgetString.split("e+"); + return Math.round(parseFloat(budget[0]) * Math.pow(10, parseInt(budget[1]))); + +}; + +function getDateTime(timeString) { + const timeZone = 'Z'; + return new Date("1999-01-01T0" + timeString + timeZone); +} + +module.exports = parseWarLog; diff --git a/api/signature-tool/signature-tool.js b/api/tools/signature-tool.js similarity index 100% rename from api/signature-tool/signature-tool.js rename to api/tools/signature-tool.js diff --git a/static/src/app/app.component.ts b/static/src/app/app.component.ts index 2b844b7..51736c3 100644 --- a/static/src/app/app.component.ts +++ b/static/src/app/app.component.ts @@ -1,4 +1,4 @@ -import {Component, HostListener} from '@angular/core'; +import {Component} from '@angular/core'; import {NavigationEnd, NavigationStart, Router} from '@angular/router'; import {LoginService} from './services/login-service/login-service'; import {PromotionService} from "./services/promotion-service/promotion.service"; @@ -30,7 +30,7 @@ export class AppComponent { } if (event instanceof NavigationEnd) { this.loading = false; - if (router.url.includes('stats') || router.url.includes('overview')) { + if (router.url.includes('overview')) { window.scrollTo({left: 0, top: 0, behavior: 'smooth'}); } } From db48cd8ef6fb8a0c1742af72639fc8d154d18f6c Mon Sep 17 00:00:00 2001 From: Florian Hartwich Date: Sat, 21 Oct 2017 10:41:49 +0200 Subject: [PATCH 02/19] Add revive and flag parsing --- api/tools/log-parse-tool.js | 48 +++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/api/tools/log-parse-tool.js b/api/tools/log-parse-tool.js index 192ce94..dd0d225 100644 --- a/api/tools/log-parse-tool.js +++ b/api/tools/log-parse-tool.js @@ -12,7 +12,6 @@ const parseWarLog = (lineArray, war) => { const flag = []; const transport = []; const playerNames = []; - const addPlayerIfNotExists = (playerName) => { if (playerName !== 'Error: No unit' && !arrayContains(playerNames, playerName)) { playerNames.push(playerName); @@ -45,7 +44,18 @@ const parseWarLog = (lineArray, war) => { if (line.includes("Fahne")) { clean.push(line); + const playerName = line.substring(line.lastIndexOf("t von ") + 6, line.lastIndexOf(" :OPT LOG END")); + const flagFraction = line.includes('NATO Flagge') ? 'BLUFOR' : 'OPFOR'; + const capture = !!line.includes('Flagge erobert'); + flag.push({ + warId: 'sdf89uiz786', + time: getDateTime(line.split(" ")[5]), + player: playerName, + flagFraction: flagFraction, + capture: capture + }); + addPlayerIfNotExists(playerName); } if (line.includes("Punkte")) { @@ -71,24 +81,47 @@ const parseWarLog = (lineArray, war) => { if (line.includes("Revive")) { clean.push(line); - //console.log(line); + + const stabilized = !!line.includes('stabilisiert'); + + const medicName = line.substring(line.lastIndexOf("wurde von ") + 10, line.lastIndexOf(stabilized ? ' stabilisiert' : ' wiederbelebt')); + const medicNameArray = medicName.split(" "); + const medicFraction = medicNameArray[medicNameArray.length - 1] === "(WEST)" ? "BLUFOR" : "OPFOR"; + const sanitizedMedicName = medicName.substring(0, medicName.indexOf(medicNameArray[medicNameArray.length - 1]) - 1); + + const patientName = line.substring(line.lastIndexOf("|| ") + 3, line.lastIndexOf(" wurde von")); + const patientNameArray = patientName.split(" "); + const patientFraction = patientNameArray[patientNameArray.length - 1] === "(WEST)" ? "BLUFOR" : "OPFOR"; + const sanitizedPatientName = patientName.substring(0, patientName.indexOf(patientNameArray[patientNameArray.length - 1]) - 1); + + revive.push({ + warId: 'asfddf', + time: getDateTime(line.split(" ")[5]), + stabilized: stabilized, + medic: sanitizedMedicName, + patient: sanitizedPatientName + }); + + addPlayerIfNotExists(sanitizedMedicName); + addPlayerIfNotExists(sanitizedPatientName); } if (line.includes("Transport ||")) { clean.push(line); const driverName = line.substring(line.lastIndexOf("wurde von ") + 10, line.lastIndexOf(" eingeflogen")); const driverNameArray = driverName.split(" "); - const driverFraction = driverNameArray[driverNameArray.length-1] === "(WEST)" ? "BLUFOR" : "OPFOR"; - const sanitizedDriverName = driverName.substring(0, driverName.indexOf(driverNameArray[driverNameArray.length-1])-1); + const driverFraction = driverNameArray[driverNameArray.length - 1] === "(WEST)" ? "BLUFOR" : "OPFOR"; + const sanitizedDriverName = driverName.substring(0, driverName.indexOf(driverNameArray[driverNameArray.length - 1]) - 1); const passengerName = line.substring(line.lastIndexOf("|| ") + 3, line.lastIndexOf(" wurde von")); const passengerNameArray = passengerName.split(" "); - const passengerFraction = passengerNameArray[passengerNameArray.length-1] === "(WEST)" ? "BLUFOR" : "OPFOR"; - const sanitizedPassengerName = passengerName.substring(0, passengerName.indexOf(passengerNameArray[passengerNameArray.length-1])-1); + const passengerFraction = passengerNameArray[passengerNameArray.length - 1] === "(WEST)" ? "BLUFOR" : "OPFOR"; + const sanitizedPassengerName = passengerName.substring(0, passengerName.indexOf(passengerNameArray[passengerNameArray.length - 1]) - 1); const distance = parseInt(line.substring(line.lastIndexOf("eingeflogen (") + 13, line.lastIndexOf("m)") - 1)); transport.push({ war: "blablub7z8", + time: getDateTime(line.split(" ")[5]), driver: sanitizedDriverName, passenger: sanitizedPassengerName, distance: distance @@ -99,7 +132,8 @@ const parseWarLog = (lineArray, war) => { } }); // - playerNames.forEach(budg => console.log(budg)); + // revive.forEach(budg => console.log(budg)); + // console.log(revive.length) }; function getRespawnEntry(respawn, playerName) { From 2d9167b172971ea765855a3593c2fce0d1f869b9 Mon Sep 17 00:00:00 2001 From: Florian Hartwich Date: Sat, 21 Oct 2017 11:32:25 +0200 Subject: [PATCH 03/19] create player list & kill log parse --- api/tools/log-parse-tool.js | 93 +++++++++++++++++-------------- api/{middleware => tools}/util.js | 6 +- 2 files changed, 53 insertions(+), 46 deletions(-) rename api/{middleware => tools}/util.js (73%) diff --git a/api/tools/log-parse-tool.js b/api/tools/log-parse-tool.js index dd0d225..77d6f2b 100644 --- a/api/tools/log-parse-tool.js +++ b/api/tools/log-parse-tool.js @@ -1,6 +1,6 @@ "use strict"; -const arrayContains = require('../middleware/util').arrayContains; +const arrayContains = require('./util').arrayContains; const parseWarLog = (lineArray, war) => { const clean = []; @@ -11,21 +11,34 @@ const parseWarLog = (lineArray, war) => { const revive = []; const flag = []; const transport = []; - const playerNames = []; - const addPlayerIfNotExists = (playerName) => { - if (playerName !== 'Error: No unit' && !arrayContains(playerNames, playerName)) { - playerNames.push(playerName); - } + const players = []; + const addPlayersIfNotExists = (inputPlayers) => { + inputPlayers.forEach(player => { + if (player && player.name !== 'Error: No unit' && !arrayContains(players, player)) { + player['warId'] = 'asd78zr3h8szfd7'; + players.push(player); + } + }) }; lineArray.forEach(line => { - if (line.includes("Abschuss")) { + if (line.includes("Abschuss") && !line.includes('Fahrzeug')) { clean.push(line); - // const kill = line.split(" "); - // for (let i=0; i< kill.length; i++ ) { - // console.log(i + " +++ " + kill[i]); - // } + const shooterString = line.substring(line.lastIndexOf(" von: ") + 6, line.lastIndexOf(". :OPT LOG END")); + const shooter = getPlayerAndFractionFromString(shooterString); + const targetString = line.substring(line.lastIndexOf(" || ") + 4, line.lastIndexOf(' von:')); + const target = getPlayerAndFractionFromString(targetString); + + kills.push({ + warId: 'asdfaew34tg', + time: getDateTime(line.split(" ")[5]), + shooter: shooter ? shooter.name : null, + target: target ? target.name : null, + friendlyFire: target && shooter ? target.fraction === shooter.fraction : false + }); + + addPlayersIfNotExists([shooter, target]); } if (line.includes("Budget")) { @@ -55,7 +68,6 @@ const parseWarLog = (lineArray, war) => { flagFraction: flagFraction, capture: capture }); - addPlayerIfNotExists(playerName); } if (line.includes("Punkte")) { @@ -74,66 +86,51 @@ const parseWarLog = (lineArray, war) => { clean.push(line); const resp = line.split(" "); const playerName = line.substring(line.lastIndexOf("Spieler:") + 9, line.lastIndexOf("-") - 1); - respawn.push(getRespawnEntry(resp, playerName)); - addPlayerIfNotExists(playerName); } if (line.includes("Revive")) { clean.push(line); - const stabilized = !!line.includes('stabilisiert'); - const medicName = line.substring(line.lastIndexOf("wurde von ") + 10, line.lastIndexOf(stabilized ? ' stabilisiert' : ' wiederbelebt')); - const medicNameArray = medicName.split(" "); - const medicFraction = medicNameArray[medicNameArray.length - 1] === "(WEST)" ? "BLUFOR" : "OPFOR"; - const sanitizedMedicName = medicName.substring(0, medicName.indexOf(medicNameArray[medicNameArray.length - 1]) - 1); - + const medic = getPlayerAndFractionFromString(medicName); const patientName = line.substring(line.lastIndexOf("|| ") + 3, line.lastIndexOf(" wurde von")); - const patientNameArray = patientName.split(" "); - const patientFraction = patientNameArray[patientNameArray.length - 1] === "(WEST)" ? "BLUFOR" : "OPFOR"; - const sanitizedPatientName = patientName.substring(0, patientName.indexOf(patientNameArray[patientNameArray.length - 1]) - 1); + const patient = getPlayerAndFractionFromString(patientName); revive.push({ warId: 'asfddf', time: getDateTime(line.split(" ")[5]), stabilized: stabilized, - medic: sanitizedMedicName, - patient: sanitizedPatientName + medic: medic.name, + patient: patientName }); - addPlayerIfNotExists(sanitizedMedicName); - addPlayerIfNotExists(sanitizedPatientName); + addPlayersIfNotExists([medic, patient]); } if (line.includes("Transport ||")) { clean.push(line); - const driverName = line.substring(line.lastIndexOf("wurde von ") + 10, line.lastIndexOf(" eingeflogen")); - const driverNameArray = driverName.split(" "); - const driverFraction = driverNameArray[driverNameArray.length - 1] === "(WEST)" ? "BLUFOR" : "OPFOR"; - const sanitizedDriverName = driverName.substring(0, driverName.indexOf(driverNameArray[driverNameArray.length - 1]) - 1); - - const passengerName = line.substring(line.lastIndexOf("|| ") + 3, line.lastIndexOf(" wurde von")); - const passengerNameArray = passengerName.split(" "); - const passengerFraction = passengerNameArray[passengerNameArray.length - 1] === "(WEST)" ? "BLUFOR" : "OPFOR"; - const sanitizedPassengerName = passengerName.substring(0, passengerName.indexOf(passengerNameArray[passengerNameArray.length - 1]) - 1); + const driverString = line.substring(line.lastIndexOf("wurde von ") + 10, line.lastIndexOf(" eingeflogen")); + const driver = getPlayerAndFractionFromString(driverString); + const passengerString = line.substring(line.lastIndexOf("|| ") + 3, line.lastIndexOf(" wurde von")); + const passenger = getPlayerAndFractionFromString(passengerString); const distance = parseInt(line.substring(line.lastIndexOf("eingeflogen (") + 13, line.lastIndexOf("m)") - 1)); transport.push({ war: "blablub7z8", time: getDateTime(line.split(" ")[5]), - driver: sanitizedDriverName, - passenger: sanitizedPassengerName, + driver: driver.name, + passenger: passenger.name, distance: distance }); - addPlayerIfNotExists(sanitizedDriverName); - addPlayerIfNotExists(sanitizedPassengerName); + addPlayersIfNotExists([driver, passenger]); } }); - // - // revive.forEach(budg => console.log(budg)); - // console.log(revive.length) + + players.forEach(player => console.log(player)) + console.log(players.length) + }; function getRespawnEntry(respawn, playerName) { @@ -163,6 +160,16 @@ function getBudgetEntry(budg) { } } +function getPlayerAndFractionFromString(nameAndFractionString) { + const nameArray = nameAndFractionString.split(" "); + const fraction = nameArray[nameArray.length - 1] === "(WEST)" ? "BLUFOR" : "OPFOR"; + const name = nameAndFractionString.substring(0, nameAndFractionString.indexOf(nameArray[nameArray.length - 1]) - 1); + // do not return player for "Selbstverschulden" + if (name) { + return {name: name, fraction: fraction}; + } +} + const transformMoneyString = (budgetString) => { if (!budgetString.includes("e+")) { return parseInt(budgetString); diff --git a/api/middleware/util.js b/api/tools/util.js similarity index 73% rename from api/middleware/util.js rename to api/tools/util.js index 233b5b0..8c2d93e 100644 --- a/api/middleware/util.js +++ b/api/tools/util.js @@ -11,11 +11,11 @@ const sortCollectionBy = (collection, key) => { return collection; }; -const arrayContains = (arr, user) => { +const playerArrayContains = (arr, item) => { let i = 0, count = arr.length, matchFound = false; for(; i < count; i++) { - if (arr[i] === user) { + if (arr[i].name === item.name && arr[i].fraction === item.fraction) { matchFound = true; break; } @@ -25,4 +25,4 @@ const arrayContains = (arr, user) => { }; exports.sortCollection = sortCollectionBy; -exports.arrayContains = arrayContains; +exports.arrayContains = playerArrayContains; From 35f6ac04b3455fa82aa8a2d149d6ccf02294e6f1 Mon Sep 17 00:00:00 2001 From: Florian Hartwich Date: Sat, 21 Oct 2017 12:11:32 +0200 Subject: [PATCH 04/19] Finish parse tool --- api/models/war.js | 32 +++++- api/routes/wars.js | 16 +-- api/tools/log-parse-tool.js | 199 ++++++++++++++++++++---------------- 3 files changed, 150 insertions(+), 97 deletions(-) diff --git a/api/models/war.js b/api/models/war.js index b89bcae..d059d44 100644 --- a/api/models/war.js +++ b/api/models/war.js @@ -10,19 +10,16 @@ const WarSchema = new Schema({ }, date: { type: Date, - required: true }, ptBlufor: { type: Number, get: v => Math.round(v), set: v => Math.round(v), - required: true }, ptOpfor: { type: Number, get: v => Math.round(v), set: v => Math.round(v), - required: true }, playersBlufor: { type: Number, @@ -38,8 +35,33 @@ const WarSchema = new Schema({ }, campaign: { type: mongoose.Schema.Types.ObjectId, - ref: 'Campaign' - } + ref: 'Campaign', + required: true + }, + budgetBlufor: { + type: Number, + get: v => Math.round(v), + set: v => Math.round(v), + default: 0 + }, + budgetOpfor: { + type: Number, + get: v => Math.round(v), + set: v => Math.round(v), + default: 0 + }, + endBudgetBlufor: { + type: Number, + get: v => Math.round(v), + set: v => Math.round(v), + default: 0 + }, + endBudgetOpfor: { + type: Number, + get: v => Math.round(v), + set: v => Math.round(v), + default: 0 + }, }, { collection: 'war', timestamps: {createdAt: 'timestamp'} diff --git a/api/routes/wars.js b/api/routes/wars.js index 33866b2..b041145 100644 --- a/api/routes/wars.js +++ b/api/routes/wars.js @@ -64,20 +64,24 @@ wars.route('/') .post(apiAuthenticationMiddleware, checkMT, upload.single('log'), (req, res, next) => { let body = req.body; - const war = new WarModel(body); + const bodyWar = new WarModel(body); if (req.file) { + // bodyWar.save((err, war) => { + // if (err) { + // return next(err); + // } fs.readFile(req.file.buffer, (file, err) => { if (err) { return next(err); } + const lineArray = file.toString().split("\n"); - parseWarLog(lineArray, {}); - + res.locals.items = parseWarLog(lineArray, bodyWar); + res.locals.processed = true; + next(); }); - res.locals.processed = true; - return next(); - + // }) } else { const err = new Error('no Logfile provided'); err.status = codes.wrongmediasend; diff --git a/api/tools/log-parse-tool.js b/api/tools/log-parse-tool.js index 77d6f2b..7bf0ef0 100644 --- a/api/tools/log-parse-tool.js +++ b/api/tools/log-parse-tool.js @@ -1,38 +1,45 @@ -"use strict"; +'use strict'; const arrayContains = require('./util').arrayContains; const parseWarLog = (lineArray, war) => { - const clean = []; - const budget = []; - const points = []; - const kills = []; - const respawn = []; - const revive = []; - const flag = []; - const transport = []; - const players = []; + const stats = { + war: war, + clean: [], + budget: [], + points: [], + kills: [], + respawn: [], + revive: [], + flag: [], + transport: [], + players: [] + }; + const addPlayersIfNotExists = (inputPlayers) => { inputPlayers.forEach(player => { - if (player && player.name !== 'Error: No unit' && !arrayContains(players, player)) { - player['warId'] = 'asd78zr3h8szfd7'; - players.push(player); + if (player && !arrayContains(stats.players, player)) { + player['warId'] = war._id; + stats.players.push(player); } }) }; lineArray.forEach(line => { - if (line.includes("Abschuss") && !line.includes('Fahrzeug')) { - clean.push(line); - const shooterString = line.substring(line.lastIndexOf(" von: ") + 6, line.lastIndexOf(". :OPT LOG END")); + /** + * KILLS + */ + if (line.includes('Abschuss') && !line.includes('Fahrzeug')) { + stats.clean.push(line); + const shooterString = line.substring(line.lastIndexOf(' von: ') + 6, line.lastIndexOf('. :OPT LOG END')); const shooter = getPlayerAndFractionFromString(shooterString); - const targetString = line.substring(line.lastIndexOf(" || ") + 4, line.lastIndexOf(' von:')); + const targetString = line.substring(line.lastIndexOf(' || ') + 4, line.lastIndexOf(' von:')); const target = getPlayerAndFractionFromString(targetString); - kills.push({ - warId: 'asdfaew34tg', - time: getDateTime(line.split(" ")[5]), + stats.kills.push({ + war: war._id, + time: getDateTime(line.split(' ')[5]), shooter: shooter ? shooter.name : null, target: target ? target.name : null, friendlyFire: target && shooter ? target.fraction === shooter.fraction : false @@ -41,65 +48,80 @@ const parseWarLog = (lineArray, war) => { addPlayersIfNotExists([shooter, target]); } - if (line.includes("Budget")) { - clean.push(line); - const budg = line.split(" "); - if (line.includes("Endbudget")) { - war["endBudgetBlufor"] = transformMoneyString(budg[11]); - war['endBudgetOpfor'] = transformMoneyString(budg[14]); - } else if (line.includes("Startbudget")) { - war["budgetBlufor"] = transformMoneyString(budg[11]); - war["budgetOpfor"] = transformMoneyString(budg[14]); + /** + * BUDGET + */ + if (line.includes('Budget')) { + stats.clean.push(line); + const budg = line.split(' '); + if (line.includes('Endbudget')) { + stats.war['endBudgetBlufor'] = transformMoneyString(budg[11]); + stats.war['endBudgetOpfor'] = transformMoneyString(budg[14]); + } else if (line.includes('Startbudget')) { + stats.war['budgetBlufor'] = transformMoneyString(budg[11]); + stats.war['budgetOpfor'] = transformMoneyString(budg[14]); } else { - budget.push(getBudgetEntry(budg)); + stats.budget.push(getBudgetEntry(budg, war._id)); } } - if (line.includes("Fahne")) { - clean.push(line); - const playerName = line.substring(line.lastIndexOf("t von ") + 6, line.lastIndexOf(" :OPT LOG END")); + /** + * FLAG + */ + if (line.includes('Fahne')) { + stats.clean.push(line); + const playerName = line.substring(line.lastIndexOf('t von ') + 6, line.lastIndexOf(' :OPT LOG END')); const flagFraction = line.includes('NATO Flagge') ? 'BLUFOR' : 'OPFOR'; const capture = !!line.includes('Flagge erobert'); - flag.push({ - warId: 'sdf89uiz786', - time: getDateTime(line.split(" ")[5]), + stats.flag.push({ + war: war._id, + time: getDateTime(line.split(' ')[5]), player: playerName, flagFraction: flagFraction, capture: capture }); } - if (line.includes("Punkte")) { - clean.push(line); - const pt = line.split(" "); + /** + * POINTS + */ + if (line.includes('Punkte')) { + stats.clean.push(line); + const pt = line.split(' '); - if (line.includes("Endpunktestand")) { - war['ptBlufor'] = parseInt(pt[11]); - war['ptOpfor'] = parseInt(pt[14].slice(0, -1)); + if (line.includes('Endpunktestand')) { + stats.war['ptBlufor'] = parseInt(pt[11]); + stats.war['ptOpfor'] = parseInt(pt[14].slice(0, -1)); } else { - points.push(getPointsEntry(pt)) + stats.points.push(getPointsEntry(pt, war._id)) } } - if (line.includes("Respawn")) { - clean.push(line); - const resp = line.split(" "); - const playerName = line.substring(line.lastIndexOf("Spieler:") + 9, line.lastIndexOf("-") - 1); - respawn.push(getRespawnEntry(resp, playerName)); + /** + * RESPAWN + */ + if (line.includes('Respawn')) { + stats.clean.push(line); + const resp = line.split(' '); + const playerName = line.substring(line.lastIndexOf('Spieler:') + 9, line.lastIndexOf('-') - 1); + stats.respawn.push(getRespawnEntry(resp, playerName, war._id)); } - if (line.includes("Revive")) { - clean.push(line); + /** + * REVIVE + */ + if (line.includes('Revive')) { + stats.clean.push(line); const stabilized = !!line.includes('stabilisiert'); - const medicName = line.substring(line.lastIndexOf("wurde von ") + 10, line.lastIndexOf(stabilized ? ' stabilisiert' : ' wiederbelebt')); + const medicName = line.substring(line.lastIndexOf('wurde von ') + 10, line.lastIndexOf(stabilized ? ' stabilisiert' : ' wiederbelebt')); const medic = getPlayerAndFractionFromString(medicName); - const patientName = line.substring(line.lastIndexOf("|| ") + 3, line.lastIndexOf(" wurde von")); + const patientName = line.substring(line.lastIndexOf('|| ') + 3, line.lastIndexOf(' wurde von')); const patient = getPlayerAndFractionFromString(patientName); - revive.push({ - warId: 'asfddf', - time: getDateTime(line.split(" ")[5]), + stats.revive.push({ + war: war._id, + time: getDateTime(line.split(' ')[5]), stabilized: stabilized, medic: medic.name, patient: patientName @@ -108,17 +130,20 @@ const parseWarLog = (lineArray, war) => { addPlayersIfNotExists([medic, patient]); } - if (line.includes("Transport ||")) { - clean.push(line); - const driverString = line.substring(line.lastIndexOf("wurde von ") + 10, line.lastIndexOf(" eingeflogen")); + /** + * TRANSPORT + */ + if (line.includes('Transport ||')) { + stats.clean.push(line); + const driverString = line.substring(line.lastIndexOf('wurde von ') + 10, line.lastIndexOf(' eingeflogen')); const driver = getPlayerAndFractionFromString(driverString); - const passengerString = line.substring(line.lastIndexOf("|| ") + 3, line.lastIndexOf(" wurde von")); + const passengerString = line.substring(line.lastIndexOf('|| ') + 3, line.lastIndexOf(' wurde von')); const passenger = getPlayerAndFractionFromString(passengerString); - const distance = parseInt(line.substring(line.lastIndexOf("eingeflogen (") + 13, line.lastIndexOf("m)") - 1)); + const distance = parseInt(line.substring(line.lastIndexOf('eingeflogen (') + 13, line.lastIndexOf('m)') - 1)); - transport.push({ - war: "blablub7z8", - time: getDateTime(line.split(" ")[5]), + stats.transport.push({ + war: war._id, + time: getDateTime(line.split(' ')[5]), driver: driver.name, passenger: passenger.name, distance: distance @@ -128,60 +153,62 @@ const parseWarLog = (lineArray, war) => { } }); - players.forEach(player => console.log(player)) - console.log(players.length) + stats.war.playersBlufor = stats.players.filter(player => player.fraction === 'BLUFOR').length; + stats.war.playersOpfor = stats.players.filter(player => player.fraction === 'OPFOR').length; + + return stats; }; -function getRespawnEntry(respawn, playerName) { +const getRespawnEntry = (respawn, playerName, warId) => { return { - war: "1234567", + war: warId, time: getDateTime(respawn[5]), player: playerName } -} +}; -function getPointsEntry(pt) { +const getPointsEntry = (pt, warId) => { return { - warId: "123-xyz-123", + warId: warId, time: getDateTime(pt[5]), ptBlufor: parseInt(pt[12]), ptOpfor: parseInt(pt[15].slice(0, -1)) } -} +}; -function getBudgetEntry(budg) { +const getBudgetEntry = (budg, warId) => { return { - warId: "123-xyz-123", + warId: warId, time: getDateTime(budg[5]), - fraction: budg[9] === "NATO" ? "BLUFOR" : "OPFOR", + fraction: budg[9] === 'NATO' ? 'BLUFOR' : 'OPFOR', oldBudget: transformMoneyString(budg[11]), newBudget: transformMoneyString(budg[14]) } -} +}; -function getPlayerAndFractionFromString(nameAndFractionString) { - const nameArray = nameAndFractionString.split(" "); - const fraction = nameArray[nameArray.length - 1] === "(WEST)" ? "BLUFOR" : "OPFOR"; +const getPlayerAndFractionFromString = (nameAndFractionString) => { + const nameArray = nameAndFractionString.split(' '); + const fraction = nameArray[nameArray.length - 1] === '(WEST)' ? 'BLUFOR' : 'OPFOR'; const name = nameAndFractionString.substring(0, nameAndFractionString.indexOf(nameArray[nameArray.length - 1]) - 1); - // do not return player for "Selbstverschulden" - if (name) { + // do not return player for 'Selbstverschulden' + if (name || name === 'Error: No unit') { return {name: name, fraction: fraction}; } -} +}; const transformMoneyString = (budgetString) => { - if (!budgetString.includes("e+")) { + if (!budgetString.includes('e+')) { return parseInt(budgetString); } - const budget = budgetString.split("e+"); + const budget = budgetString.split('e+'); return Math.round(parseFloat(budget[0]) * Math.pow(10, parseInt(budget[1]))); }; -function getDateTime(timeString) { +const getDateTime = (timeString) => { const timeZone = 'Z'; - return new Date("1999-01-01T0" + timeString + timeZone); -} + return new Date('1999-01-01T0' + timeString + timeZone); +}; module.exports = parseWarLog; From 1acaba5a60324cef5723ec00a7fb8aab40f695cf Mon Sep 17 00:00:00 2001 From: Florian Hartwich Date: Sat, 21 Oct 2017 14:54:58 +0200 Subject: [PATCH 05/19] finish basci backend implementation --- api/routes/wars.js | 28 +++++++++++++++++----------- api/tools/log-parse-tool.js | 22 ++++++++++++++++------ package.json | 2 +- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/api/routes/wars.js b/api/routes/wars.js index b041145..4666402 100644 --- a/api/routes/wars.js +++ b/api/routes/wars.js @@ -63,25 +63,31 @@ wars.route('/') }) .post(apiAuthenticationMiddleware, checkMT, upload.single('log'), (req, res, next) => { - let body = req.body; - const bodyWar = new WarModel(body); + const body = req.body; + const warBody = new WarModel(body); if (req.file) { - // bodyWar.save((err, war) => { - // if (err) { - // return next(err); - // } fs.readFile(req.file.buffer, (file, err) => { if (err) { return next(err); } - const lineArray = file.toString().split("\n"); - res.locals.items = parseWarLog(lineArray, bodyWar); - res.locals.processed = true; - next(); + const statsResult = parseWarLog(lineArray, warBody); + statsResult.war.save((err, war) => { + if (err) { + return next(err); + } + PlayerModel.create(statsResult.players, function (err) { + if (err) { + return next(err); + } + res.status(codes.created); + res.locals.items = war; + next(); + }); + }) }); - // }) + } else { const err = new Error('no Logfile provided'); err.status = codes.wrongmediasend; diff --git a/api/tools/log-parse-tool.js b/api/tools/log-parse-tool.js index 7bf0ef0..ad92d4a 100644 --- a/api/tools/log-parse-tool.js +++ b/api/tools/log-parse-tool.js @@ -18,7 +18,7 @@ const parseWarLog = (lineArray, war) => { const addPlayersIfNotExists = (inputPlayers) => { inputPlayers.forEach(player => { - if (player && !arrayContains(stats.players, player)) { + if (player && player.name && player.fraction && !arrayContains(stats.players, player)) { player['warId'] = war._id; stats.players.push(player); } @@ -33,7 +33,6 @@ const parseWarLog = (lineArray, war) => { stats.clean.push(line); const shooterString = line.substring(line.lastIndexOf(' von: ') + 6, line.lastIndexOf('. :OPT LOG END')); const shooter = getPlayerAndFractionFromString(shooterString); - const targetString = line.substring(line.lastIndexOf(' || ') + 4, line.lastIndexOf(' von:')); const target = getPlayerAndFractionFromString(targetString); @@ -58,6 +57,7 @@ const parseWarLog = (lineArray, war) => { stats.war['endBudgetBlufor'] = transformMoneyString(budg[11]); stats.war['endBudgetOpfor'] = transformMoneyString(budg[14]); } else if (line.includes('Startbudget')) { + stats.war.date = new Date(budg[0].substr(0, budg[0].length - 1).split('/').join('-') + 'T22:00:00.000+02:00'); stats.war['budgetBlufor'] = transformMoneyString(budg[11]); stats.war['budgetOpfor'] = transformMoneyString(budg[14]); } else { @@ -114,7 +114,8 @@ const parseWarLog = (lineArray, war) => { if (line.includes('Revive')) { stats.clean.push(line); const stabilized = !!line.includes('stabilisiert'); - const medicName = line.substring(line.lastIndexOf('wurde von ') + 10, line.lastIndexOf(stabilized ? ' stabilisiert' : ' wiederbelebt')); + const medicName = line.substring(line.lastIndexOf('wurde von ') + 10, + line.lastIndexOf(stabilized ? ' stabilisiert' : ' wiederbelebt')); const medic = getPlayerAndFractionFromString(medicName); const patientName = line.substring(line.lastIndexOf('|| ') + 3, line.lastIndexOf(' wurde von')); const patient = getPlayerAndFractionFromString(patientName); @@ -153,11 +154,20 @@ const parseWarLog = (lineArray, war) => { } }); + for (let i = 0; i < stats.players.length; i++) { + const playerName = stats.players[i].name; + stats.players[i]['respawn'] = stats.respawn.filter(res => res.player === playerName).length; + stats.players[i]['kill'] = stats.kills.filter(kill => kill.shooter === playerName && !kill.friendlyFire).length; + stats.players[i]['friendlyFire'] = stats.kills.filter(kill => kill.shooter === playerName && kill.friendlyFire).length; + stats.players[i]['death'] = stats.kills.filter(kill => kill.target === playerName).length; + stats.players[i]['revive'] = stats.revive.filter(rev => rev.medic === playerName && !rev.stabilized).length; + stats.players[i]['flagTouch'] = stats.flag.filter(flag => flag.player === playerName).length; + } + stats.war.playersBlufor = stats.players.filter(player => player.fraction === 'BLUFOR').length; stats.war.playersOpfor = stats.players.filter(player => player.fraction === 'OPFOR').length; return stats; - }; const getRespawnEntry = (respawn, playerName, warId) => { @@ -189,10 +199,10 @@ const getBudgetEntry = (budg, warId) => { const getPlayerAndFractionFromString = (nameAndFractionString) => { const nameArray = nameAndFractionString.split(' '); - const fraction = nameArray[nameArray.length - 1] === '(WEST)' ? 'BLUFOR' : 'OPFOR'; + const fraction = nameArray[nameArray.length - 1] !== '(ENEMY)' ? nameArray[nameArray.length - 1] === '(WEST)' ? 'BLUFOR' : 'OPFOR' : undefined; const name = nameAndFractionString.substring(0, nameAndFractionString.indexOf(nameArray[nameArray.length - 1]) - 1); // do not return player for 'Selbstverschulden' - if (name || name === 'Error: No unit') { + if (name && name !== 'Error: No unit') { return {name: name, fraction: fraction}; } }; diff --git a/package.json b/package.json index 2ef491a..ec6edde 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opt-cc", - "version": "1.5.4", + "version": "1.6.0", "license": "MIT", "private": true, "scripts": { From 91ebda52b01284830e9e1b40014d102abeb79bb9 Mon Sep 17 00:00:00 2001 From: Florian Hartwich Date: Sat, 21 Oct 2017 15:00:49 +0200 Subject: [PATCH 06/19] compatible war upload page --- .../war-submit/war-submit.component.html | 30 ------------------- .../war-submit/war-submit.component.ts | 2 +- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/static/src/app/statistic/war-submit/war-submit.component.html b/static/src/app/statistic/war-submit/war-submit.component.html index cf7b4fd..cca4dff 100644 --- a/static/src/app/statistic/war-submit/war-submit.component.html +++ b/static/src/app/statistic/war-submit/war-submit.component.html @@ -12,36 +12,6 @@ -
- - - -
- -
- - - -
- -
- - - -
-