Add war-log upload endpoint and processing

pull/1/head
Florian Hartwich 2017-07-08 15:34:36 +02:00
parent 2fa616570c
commit 84b19310b6
10 changed files with 1748 additions and 235 deletions

View File

@ -11,5 +11,6 @@ module.exports = {
squads: '/squads', squads: '/squads',
users: '/users', users: '/users',
account: '/account', account: '/account',
request: '/request' request: '/request',
wars: '/wars'
}; };

58
api/models/player.js Normal file
View File

@ -0,0 +1,58 @@
"use strict";
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const PlayerSchema = new Schema({
name: {
type: String,
required: true
},
fraction: {
type: String,
enum: ['BLUFOR', 'OPFOR'],
required: true
},
warId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'War',
required: true
},
kill: {
type: Number,
get: v => Math.round(v),
set: v => Math.round(v),
required: true
},
death: {
type: Number,
get: v => Math.round(v),
set: v => Math.round(v),
required: true
},
friendlyFire: {
type: Number,
get: v => Math.round(v),
set: v => Math.round(v),
required: true
},
respawn: {
type: Number,
get: v => Math.round(v),
set: v => Math.round(v),
required: true
},
flagTouch: {
type: Number,
get: v => Math.round(v),
set: v => Math.round(v),
default: 0
}
}, {
collection: 'player',
timestamps: {createdAt: 'timestamp'}
});
// optional more indices
PlayerSchema.index({timestamp: 1});
module.exports = mongoose.model('Player', PlayerSchema);

35
api/models/war.js Normal file
View File

@ -0,0 +1,35 @@
"use strict";
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
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
},
bestPlayerId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Player',
default: null
}
}, {
collection: 'war',
timestamps: {createdAt: 'timestamp'}
});
// optional more indices
WarSchema.index({timestamp: 1});
module.exports = mongoose.model('War', WarSchema);

1681
api/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,8 @@
"jimp": "^0.2.27", "jimp": "^0.2.27",
"jsonwebtoken": "^7.4.0", "jsonwebtoken": "^7.4.0",
"lodash": "^4.17.4", "lodash": "^4.17.4",
"mongoose": "^4.3.0", "mkdirp": "^0.5.1",
"mongoose": "^4.11.1",
"morgan": "~1.6.1", "morgan": "~1.6.1",
"multer": "^1.3.0", "multer": "^1.3.0",
"node-sha1": "^1.0.1", "node-sha1": "^1.0.1",

150
api/routes/war.js Normal file
View File

@ -0,0 +1,150 @@
"use strict";
// modules
const fs = require('fs');
const mkdirp = require("mkdirp");
const {exec} = require('child_process');
const express = require('express');
const multer = require('multer');
const storage = multer.memoryStorage();
const upload = multer({storage: storage});
const logger = require('debug')('cc:squads');
// HTTP status codes by name
const codes = require('./http-codes');
const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
// const checkMT = require('../middleware/permission-check').checkMT();
const routerHandling = require('../middleware/router-handling');
// Mongoose Model using mongoDB
const WarModel = require('../models/war');
const wars = express.Router();
// routes **********************
wars.route('/')
// .get((req, res, next) => {
// const filter = {};
// WarModel.find(filter, {}, {sort: {date: 'asc'}}, (err, items) => {
// if (err) {
// err.status = codes.servererror;
// return next(err);
// }
// if (items) {
// res.locals.items = items;
// } else {
// res.locals.items = [];
// }
// res.locals.processed = true;
// next();
// });
// })
.post(upload.single('log'), (req, res, next) => {
const war = new WarModel(req.body);
// timestamp and default are set automatically by Mongoose Schema Validation
if (req.file) {
const timestamp = new Date();
const uploadDate = timestamp.toISOString().slice(0, 10) + '_' + timestamp.toTimeString().slice(0, 8)
const folderName = __dirname + '/../resource/logs/' + uploadDate;
mkdirp(folderName, function (err) {
if (err) {
return next(err);
}
fs.appendFile(folderName + '/war.log', new Buffer(req.file.buffer), (err) => {
if (err) {
next(err);
}
exec(__dirname + '/../war-parser/run.sh ' + folderName + ' | tee resource/logs/' + uploadDate + '/score.log' , (error, stdout, stderr) => {
console.log("log")
if (error) {
return next(error);
}
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
res.locals.items={};
return next();
});
// exec(__dirname + '/../war-parser/clean.sh ' + folderName + ' | tee resource/logs/' + uploadDate + '/clean.log' , (error) => {
// if (error) {
// return next(error);
// }
//
// });
});
});
// war.save((err) => {
// if (err) {
// err.status = codes.wrongrequest;
// err.message += ' in fields: ' + Object.getOwnPropertyNames(err.errors);
// return next(err);
// }
// res.status(codes.created);
// res.locals.items = war;
// fs.appendFile(__dirname + '/../resource/squad/' + war.id + '.png', new Buffer(req.file.buffer), (err) => {
// if (err) next(err);
// });
// next();
// })
} else {
const err = new Error('no Logfile provided');
err.status = codes.wrongmediasend;
next(err);
}
})
.all(
routerHandling.httpMethodNotAllowed
);
//
// wars.route('/:id')
// .get((req, res, next) => {
// WarModel.findById(req.params.id, (err, item) => {
// if (err) {
// err.status = codes.servererror;
// return next(err);
// }
// else if (!item) {
// err = new Error("item not found");
// err.status = codes.notfound;
// return next(err);
// }
// res.locals.items = item;
// next();
// });
// })
//
// .delete(apiAuthenticationMiddleware, checkHl, (req, res, next) => {
// WarModel.findByIdAndRemove(req.params.id, (err, item) => {
// if (err) {
// err.status = codes.wrongrequest;
// }
// else if (!item) {
// err = new Error("item not found");
// err.status = codes.notfound;
// }
//
// // delete graphic
// fs.unlink(__dirname + '/../resource/squad/' + req.params.id + '.png', (err) => {
// if (err) next(err);
// });
//
// // we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler user.use(..)
// res.locals.processed = true;
// next(err); // this works because err is in normal case undefined and that is the same as no parameter
// });
// })
//
// .all(
// routerHandling.httpMethodNotAllowed
// );
// this middleware function can be used, if you like or remove it
// it looks for object(s) in res.locals.items and if they exist, they are send to the client as json
wars.use(routerHandling.emptyResponse);
module.exports = wars;

View File

@ -31,6 +31,7 @@ const awardingRouter = require('./routes/awardings');
const requestRouter = require('./routes/request'); const requestRouter = require('./routes/request');
const signatureRouter = require('./routes/signatures'); const signatureRouter = require('./routes/signatures');
const commandRouter = require('./routes/command'); const commandRouter = require('./routes/command');
const warRouter = require('./routes/war');
// Configuration *********************************** // Configuration ***********************************
// mongoose promise setup // mongoose promise setup
@ -75,6 +76,7 @@ app.use(urls.ranks, rankRouter);
app.use(urls.decorations, decorationRouter); app.use(urls.decorations, decorationRouter);
app.use(urls.request, requestRouter); app.use(urls.request, requestRouter);
app.use(urls.awards, awardingRouter); app.use(urls.awards, awardingRouter);
app.use(urls.wars, warRouter);
app.use(urls.command, apiAuthenticationMiddleware, checkAdmin, commandRouter); app.use(urls.command, apiAuthenticationMiddleware, checkAdmin, commandRouter);
app.use(urls.account, apiAuthenticationMiddleware, checkAdmin, accountRouter); app.use(urls.account, apiAuthenticationMiddleware, checkAdmin, accountRouter);

View File

@ -1,4 +1,4 @@
"use strict" "use strict";
// modules used for graphic manipulation // modules used for graphic manipulation
const jimp = require('jimp'); const jimp = require('jimp');

View File

@ -1,20 +1,15 @@
#!/usr/bin/env bash #!/usr/bin/env bash
FILE="$1" FILE="$1/war.log"
FILTER=("Budget" "Mission" "Abschuss" "Respawn" "Punkte")
pat=$(echo ${FILTER[@]}|tr " " "|") while IFS='' read -r line || [[ -n "$line" ]]; do
case "$line" in
*"Budget"* | *"Mission"* | *"Abschuss"* | *"Respawn"* | *"Punkte"*)
while IFS= read -r line; do echo $line;
if [[ $line =~ [^[:space:]] ]]; then echo ""
RES="$(grep -Ew "$pat" <<< "$line")" ;;
if [[ ${RES} =~ [^[:space:]] ]]; then esac
echo ${RES} done < ${FILE}
echo ""
fi
fi
done < <(cat ${FILE} )
# Add OPT Scoreboard # Add OPT Scoreboard
while IFS= read -r line; do while IFS= read -r line; do

View File

@ -1,10 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
createScoreboardHeader() {
printf "%25s %8s %8s %8s %8s %8s\n" "Name" "Kill" "FF" "Death" "Respawn"
echo "---------------------------------------------------------------------------"
}
createScoreboard() { createScoreboard() {
NAME="$1" NAME="$1"
FILE="$2" FILE="$2"
@ -34,14 +29,16 @@ createScoreboard() {
esac esac
done < <(grep -- "${ESC_NAME}" ${FILE}) done < <(grep -- "${ESC_NAME}" ${FILE})
#echo {\"name\":\"$NAME\", \"kill\":${KILL}, \"ff\":${FF}, \"death\":${DEATH}, \"respawn\":${RESPAWN}}, printf "\t{\"name\":\"$NAME\", \"kill\":${KILL}, \"ff\":${FF}, \"death\":${DEATH}, \"respawn\":${RESPAWN}}"
if [[ $NAME =~ [^[:space:]] ]]; then if [[ -z ${3} ]]; then
printf "%25s %8s %8s %8s %8s %8s\n" "$NAME" $KILL $FF $DEATH $RESPAWN printf ",\n"
else
printf "\n"
fi fi
} }
FILE="$1" FILE="$1/war.log"
PLAYERS=() PLAYERS=()
while IFS='' read -r line || [[ -n "$line" ]]; do while IFS='' read -r line || [[ -n "$line" ]]; do
@ -68,10 +65,13 @@ while IFS='' read -r line || [[ -n "$line" ]]; do
fi fi
done < ${FILE} done < ${FILE}
createScoreboardHeader echo "["
for i in "${PLAYERS[@]}" for ((i=0; i<${#PLAYERS[*]}; i++));
do do
: if [[ "$((i+1))" -eq "${#PLAYERS[*]}" ]]; then
createScoreboard "$i" ${FILE} last="true"
fi
createScoreboard "${PLAYERS[i]}" ${FILE} ${last}
done done
echo "]"