add player weapon route

This commit is contained in:
2023-03-13 12:19:05 +01:00
parent fee43b1a98
commit 8340465ed2
9 changed files with 149 additions and 43 deletions
+2 -2
View File
@@ -9,7 +9,7 @@
"request": "launch", "request": "launch",
"name": "Launch Server API", "name": "Launch Server API",
"skipFiles": ["<node_internals>/**"], "skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/src/server.ts", "program": "${workspaceFolder}/src/serverMain.ts",
"preLaunchTask": "tsc: build - tsconfig.json", "preLaunchTask": "tsc: build - tsconfig.json",
"outFiles": ["${workspaceFolder}/out/**/*.js"] "outFiles": ["${workspaceFolder}/out/**/*.js"]
}, },
@@ -18,7 +18,7 @@
"request": "launch", "request": "launch",
"name": "Launch Client API", "name": "Launch Client API",
"skipFiles": ["<node_internals>/**"], "skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/src/client.ts", "program": "${workspaceFolder}/src/clientMain.ts",
"preLaunchTask": "tsc: build - tsconfig.json", "preLaunchTask": "tsc: build - tsconfig.json",
"outFiles": ["${workspaceFolder}/out/**/*.js"] "outFiles": ["${workspaceFolder}/out/**/*.js"]
} }
+3 -2
View File
@@ -1,5 +1,6 @@
import { Router } from 'express' import { Router } from 'express'
import weapons from './weapons' import weapons from './weapons'
import player from './player'
const router = Router() const router = Router()
//timeout middleware ? //timeout middleware ?
router.get('/*', (req, res, next) => { router.get('/*', (req, res, next) => {
@@ -16,7 +17,7 @@ router.get('/players/:playerId', (req, res, next) => {})
router.get('/servers/', (req, res, next) => {}) router.get('/servers/', (req, res, next) => {})
router.get('/servers/:serverId/', (req, res, next) => {}) router.get('/servers/:serverId/', (req, res, next) => {})
router.get('/servers/:serverId/players', (req, res, next) => {}) router.get('/servers/:serverId/players', (req, res, next) => {})
router.get('/servers/:serverId/players/:playerId', (req, res, next) => {}) router.get('/servers/:serverId/player/:playerId', player)
router.use('/', weapons) router.use('/servers/:serverId/weapons', weapons)
export default router export default router
+113
View File
@@ -0,0 +1,113 @@
import { RequestHandler } from 'express'
import { param } from 'express-validator'
import { validateErrors } from '../common'
import cache from '../cache/redis'
import { sql } from 'kysely'
import db from '../db/db'
const { count, max } = db.fn
const middlewares: RequestHandler[] = [
param(['serverId', 'playerId']).exists().toInt().isInt(),
validateErrors,
async (req, res) => {
const server = Number(req.params.serverId)
const player = Number(req.params.playerId)
await processPlayerWeapons(server, player)
const killsData = await cache.HGETALL(
`servers:${server}:players:${player}:weapons:kills`
)
const deathData = await cache.HGETALL(
`servers:${server}:players:${player}:weapons:deaths`
)
const data: { [x: string]: { kills: string; deaths: string } } = {}
Object.keys(killsData).forEach((key) => {
data[key] = { kills: killsData[key], deaths: deathData[key] }
})
res.status(200).send(data)
}
]
async function processPlayerWeapons(server: number, player: number) {
let last_entry =
Number(
await cache.HGET(
`servers:${server}:players:${player}:weapons`,
'last_entry'
)
) || 0
const newData = await db
.with('killdata', () =>
db
.selectFrom('kill')
.select([count('kill.id').as('num_kills'), 'kill.cause_of_death'])
.where('attacker_id', '=', player.toString())
.where('kill.id', '>', last_entry)
.where('kill.server', '=', server)
.whereRef('attacker_id', '!=', 'victim_id')
.groupBy('cause_of_death')
)
.with('deathdata', () =>
db
.selectFrom('kill')
.select([count('kill.id').as('num_deaths'), 'kill.cause_of_death'])
.where('victim_id', '=', player.toString())
.where('kill.id', '>', last_entry)
.where('kill.server', '=', server)
.groupBy('cause_of_death')
)
.selectFrom('killdata')
.select([
sql<number>`coalesce(killdata.num_kills, 0)`.as('kills'),
sql<number>`coalesce(deathdata.num_deaths, 0)`.as('deaths'),
sql<string>`COALESCE(killdata.cause_of_death, deathdata.cause_of_death)`.as(
'weapon'
),
db
.selectFrom('kill')
.select(max('kill.id').as('last_entry'))
.as('last_entry')
])
.fullJoin(
'deathdata',
'deathdata.cause_of_death',
'killdata.cause_of_death'
)
.orderBy('kills', 'desc')
.execute()
//if no new kills
if (newData.length == 0) {
return
}
last_entry = newData.reduce(
(acc, current) => (current.last_entry > acc ? current.last_entry : acc),
0
)
console.log(newData)
const promises: Promise<number>[] = []
newData.forEach(({ weapon, kills, deaths }) => {
promises.push(
cache.HINCRBY(
`servers:${server}:players:${player}:weapons:deaths`,
weapon,
deaths
),
cache.HINCRBY(
`servers:${server}:players:${player}:weapons:kills`,
weapon,
kills
)
)
})
promises.push(
cache.HSET(
`servers:${server}:players:${player}:weapons`,
'last_entry',
newData[0].last_entry
)
)
await Promise.all(promises)
}
export default middlewares
+14 -19
View File
@@ -1,32 +1,24 @@
import { Router } from 'express' import { RequestHandler } from 'express'
import { param, validationResult } from 'express-validator' import { param } from 'express-validator'
import { validateErrors } from '../common'
import cache from '../cache/redis' import cache from '../cache/redis'
import db from '../db/db' import db from '../db/db'
const router = Router()
const { count, max } = db.fn const { count, max } = db.fn
router.get( const middlewares: RequestHandler[] = [
'/servers/:serverId/weapons',
param('serverId').exists().toInt().isInt(), param('serverId').exists().toInt().isInt(),
validateErrors,
async (req, res) => { async (req, res) => {
const errors = validationResult(req)
if (!errors.isEmpty()) {
console.error(JSON.stringify(errors))
return res.status(400).json({ errors: errors.array() })
}
if (!req.params) {
res.sendStatus(500)
return
}
const server = Number(req.params.serverId) const server = Number(req.params.serverId)
await processTopWeapons(server) await processWeapons(server)
const data = await cache.HGETALL(`servers:${server}:weapons`) const data = await cache.HGETALL(`servers:${server}:weapons`)
delete data.last_entry delete data.last_entry
res.status(200).send(data) res.status(200).send(data)
} }
) ]
async function processTopWeapons(server: number) { async function processWeapons(server: number) {
let last_entry = let last_entry =
Number(await cache.HGET(`servers:${server}:weapons`, 'last_entry')) || 0 Number(await cache.HGET(`servers:${server}:weapons`, 'last_entry')) || 0
const newData = await db const newData = await db
@@ -34,7 +26,10 @@ async function processTopWeapons(server: number) {
.select([ .select([
count<number>('kill.id').as('num_kills'), count<number>('kill.id').as('num_kills'),
'kill.cause_of_death', 'kill.cause_of_death',
max('kill.id').as('last_entry') db
.selectFrom('kill')
.select(max('kill.id').as('last_entry'))
.as('last_entry')
]) ])
.where('server', '=', server) .where('server', '=', server)
.where('kill.id', '>', last_entry) .where('kill.id', '>', last_entry)
@@ -60,4 +55,4 @@ async function processTopWeapons(server: number) {
await Promise.all(promises) await Promise.all(promises)
} }
export default router export default middlewares
View File
+11
View File
@@ -1,3 +1,5 @@
import { RequestHandler } from 'express'
import { Result, validationResult } from 'express-validator'
import http from 'http' import http from 'http'
import https from 'https' import https from 'https'
@@ -29,3 +31,12 @@ export function GetRequest(url: string) {
.end() .end()
}) })
} }
export const validateErrors: RequestHandler = (req, res, next) => {
const errors = validationResult(req)
if (!errors.isEmpty()) {
console.error(JSON.stringify(errors))
return res.status(400).json({ errors: errors.array() })
}
next()
}
+3 -7
View File
@@ -1,5 +1,5 @@
import { Router } from 'express' import { Router } from 'express'
import { GetRequest } from '../common' import { GetRequest, validateErrors } from '../common'
import { FindServer, CreateServer } from '../db/db' import { FindServer, CreateServer } from '../db/db'
import { body, validationResult } from 'express-validator' import { body, validationResult } from 'express-validator'
@@ -37,12 +37,8 @@ router.post(
.toInt() .toInt()
.isInt({ min: 1, max: 65535 }) .isInt({ min: 1, max: 65535 })
.withMessage('must be between 1 and 65535'), .withMessage('must be between 1 and 65535'),
async (req, res, next) => { validateErrors,
const errors = validationResult(req) async (req, res) => {
console.log(req.body)
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() })
}
try { try {
//Check if server name isn't already in database //Check if server name isn't already in database
if (!!(await FindServer({ name: req.body.name }))) { if (!!(await FindServer({ name: req.body.name }))) {
+3 -13
View File
@@ -3,6 +3,7 @@ import expressBasicAuth from 'express-basic-auth'
import { body, header, validationResult } from 'express-validator' import { body, header, validationResult } from 'express-validator'
import register from './register' import register from './register'
import { CreateKillRecord, CheckServerToken } from '../db/db' import { CreateKillRecord, CheckServerToken } from '../db/db'
import { validateErrors } from '../common'
const router = Router() const router = Router()
@@ -17,14 +18,7 @@ router.post(
.bail() .bail()
.contains('Basic') .contains('Basic')
.withMessage('Authorization Token is not Basic'), .withMessage('Authorization Token is not Basic'),
(req, res, next) => { validateErrors,
const errors = validationResult(req)
if (!errors.isEmpty()) {
console.log(JSON.stringify(errors))
return res.status(403).json({ errors: errors.array() })
}
next()
},
//Huge mess to retrieve server id from expressBasicAuth. We probably should fix it. //Huge mess to retrieve server id from expressBasicAuth. We probably should fix it.
(req, res, next) => { (req, res, next) => {
if (!req) res.sendStatus(500) if (!req) res.sendStatus(500)
@@ -118,12 +112,8 @@ router.post(
min: 0 min: 0
}), }),
body(['cause_of_death', 'victim_id'], 'mandatory').exists().notEmpty(), body(['cause_of_death', 'victim_id'], 'mandatory').exists().notEmpty(),
validateErrors,
(req, res) => { (req, res) => {
const errors = validationResult(req)
if (!errors.isEmpty()) {
console.error(JSON.stringify(errors))
return res.status(400).json({ errors: errors.array() })
}
const { const {
killstat_version, killstat_version,
match_id, match_id,
View File