big refactor for lots of filtering
This commit is contained in:
Vendored
+61
-3
@@ -9,7 +9,7 @@ import cache from './redis'
|
|||||||
export async function getWeaponReport(
|
export async function getWeaponReport(
|
||||||
weapon: string,
|
weapon: string,
|
||||||
server?: number,
|
server?: number,
|
||||||
player?: number
|
player?: string
|
||||||
) {
|
) {
|
||||||
const serverPrefix = server ? `servers:${server}:` : ''
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
const playerPrefix = player ? `players:${player}:` : ''
|
const playerPrefix = player ? `players:${player}:` : ''
|
||||||
@@ -19,8 +19,66 @@ export async function getWeaponReport(
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWeaponList(server?: string, player?: string) {
|
export function getWeaponSet(server?: number, player?: string) {
|
||||||
const serverPrefix = server ? `servers:${server}:` : ''
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
const playerPrefix = player ? `players:${player}:` : ''
|
const playerPrefix = player ? `players:${player}:` : ''
|
||||||
return cache.GET(serverPrefix + playerPrefix + `weapons:processedList`)
|
const cacheLocation = serverPrefix + playerPrefix + `weapons`
|
||||||
|
return cache.SMEMBERS(cacheLocation)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the processed list of weapons
|
||||||
|
* @param server
|
||||||
|
* @param player
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
|
export async function getWeaponList(server?: string, player?: string) {
|
||||||
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
|
const playerPrefix = player ? `players:${player}:` : ''
|
||||||
|
return JSON.parse(
|
||||||
|
(await cache.GET(serverPrefix + playerPrefix + `weapons:processedList`)) ||
|
||||||
|
'{}'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show processed data for a player
|
||||||
|
* @param player
|
||||||
|
* @param server
|
||||||
|
* @param weapon
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function getPlayerReport(
|
||||||
|
player: string,
|
||||||
|
server?: number,
|
||||||
|
weapon?: string
|
||||||
|
) {
|
||||||
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
|
const weaponPrefix = weapon ? `weapons:${weapon}:` : ''
|
||||||
|
const cacheLocation = serverPrefix + weaponPrefix + `players:` + player
|
||||||
|
const data = await cache.HGETALL(cacheLocation)
|
||||||
|
delete data.last_entry
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows processed list of players
|
||||||
|
* @param server
|
||||||
|
* @param weapon
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
|
export async function getPlayerList(server?: number, weapon?: string) {
|
||||||
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
|
const weaponPrefix = weapon ? `weapons:${weapon}:` : ''
|
||||||
|
return JSON.parse(
|
||||||
|
(await cache.GET(serverPrefix + weaponPrefix + `players:processedList`)) ||
|
||||||
|
'{}'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPlayerSet(server?: number, weapon?: string) {
|
||||||
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
|
const weaponPrefix = weapon ? `weapons:${weapon}:` : ''
|
||||||
|
const cacheLocation = serverPrefix + weaponPrefix + `players`
|
||||||
|
return cache.SMEMBERS(cacheLocation)
|
||||||
}
|
}
|
||||||
|
|||||||
+69
-67
@@ -1,91 +1,93 @@
|
|||||||
import { Router } from 'express'
|
import { Router } from 'express'
|
||||||
import { param } from 'express-validator'
|
import { param, query } from 'express-validator'
|
||||||
import { validateErrors } from '../common'
|
import { validateErrors } from '../common'
|
||||||
import serverPlayers from './routes/serverPlayers'
|
|
||||||
import serverList from './routes/serverList'
|
import serverList from './routes/serverList'
|
||||||
import player from './routes/player'
|
import {
|
||||||
import { getWeaponList, getWeaponReport } from '../cache/cacheUtils'
|
getWeaponList,
|
||||||
|
getWeaponReport,
|
||||||
|
getPlayerReport,
|
||||||
|
getPlayerList
|
||||||
|
} from '../cache/cacheUtils'
|
||||||
const router = Router()
|
const router = Router()
|
||||||
//timeout middleware ?
|
//timeout middleware ?
|
||||||
router.get('/*', (req, res, next) => {
|
router.get('/*', (req, res, next) => {
|
||||||
next()
|
next()
|
||||||
})
|
})
|
||||||
|
|
||||||
router.get('/weapons/', async (req, res) => {
|
|
||||||
const data = JSON.parse((await getWeaponList()) || '{}')
|
|
||||||
res.status(200).send(data)
|
|
||||||
})
|
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
'/weapons/:weaponId',
|
'/weapons/:weaponId',
|
||||||
param(['weaponId']).exists().isString(),
|
param(['weaponId']).exists().isString(),
|
||||||
|
query(['player', 'server']).optional().toInt().isInt(),
|
||||||
validateErrors,
|
validateErrors,
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const weapon = req.params.weaponId
|
const data = await getWeaponReport(
|
||||||
const data = await getWeaponReport(weapon)
|
req.params.weaponId,
|
||||||
|
Number(req.query.server) || undefined,
|
||||||
|
req.query.player?.toString()
|
||||||
|
)
|
||||||
|
res.status(200).send(data)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
'/weapons/',
|
||||||
|
query(['player', 'server']).optional().toInt().isInt(),
|
||||||
|
validateErrors,
|
||||||
|
async (req, res) => {
|
||||||
|
const data = await getWeaponList(
|
||||||
|
req.query.server?.toString(),
|
||||||
|
req.query.player?.toString()
|
||||||
|
)
|
||||||
|
res.status(200).send(data)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
'/players/:playerId',
|
||||||
|
param(['playerId']).exists().toInt().isInt(),
|
||||||
|
query(['server']).optional().toInt().isInt(),
|
||||||
|
query('weapon').optional().isString(),
|
||||||
|
validateErrors,
|
||||||
|
async (req, res) => {
|
||||||
|
const data = await getPlayerReport(
|
||||||
|
req.params.playerId,
|
||||||
|
Number(req.query.server) || undefined,
|
||||||
|
req.query.weapon?.toString()
|
||||||
|
)
|
||||||
|
if (!req.query.weapon) {
|
||||||
|
const weapons = await getWeaponList(
|
||||||
|
req.query.server?.toString(),
|
||||||
|
req.params.playerId
|
||||||
|
)
|
||||||
|
data.weapons = weapons
|
||||||
|
} else {
|
||||||
|
data.weapons = (await getWeaponReport(
|
||||||
|
req.query.weapon.toString(),
|
||||||
|
Number(req.query.server) || undefined,
|
||||||
|
req.params.playerId
|
||||||
|
)) as any
|
||||||
|
}
|
||||||
|
res.status(200).send(data)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
'/players/',
|
||||||
|
query(['server']).optional().toInt().isInt(),
|
||||||
|
query('weapon').optional().isString(),
|
||||||
|
validateErrors,
|
||||||
|
async (req, res) => {
|
||||||
|
const data = await getPlayerList(
|
||||||
|
Number(req.query.server) || undefined,
|
||||||
|
req.query.weapon?.toString()
|
||||||
|
)
|
||||||
res.status(200).send(data)
|
res.status(200).send(data)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
//router.get('/maps/', (req, res, next) => {})
|
//router.get('/maps/', (req, res, next) => {})
|
||||||
|
|
||||||
//router.get('/players', (req, res, next) => {})
|
|
||||||
//router.get('/players/:playerId', (req, res, next) => {})
|
|
||||||
|
|
||||||
router.get('/players/:playerId/weapons')
|
|
||||||
|
|
||||||
router.get('/servers/', serverList)
|
router.get('/servers/', serverList)
|
||||||
//router.get('/servers/:serverId/', (req, res, next) => {})
|
//router.get('/servers/:serverId/', (req, res, next) => {})
|
||||||
router.get('/servers/:serverId/players', serverPlayers)
|
|
||||||
//router.get('/servers/:serverId/players/:playerId', player)
|
|
||||||
|
|
||||||
router.get(
|
|
||||||
'/servers/:serverId/players/:playerId/weapons',
|
|
||||||
param(['serverId', 'playerId']).exists().toInt().isInt(),
|
|
||||||
validateErrors,
|
|
||||||
async (req, res) => {
|
|
||||||
const data = JSON.parse(
|
|
||||||
(await getWeaponList(req.params.serverId, req.params.playerId)) || '{}'
|
|
||||||
)
|
|
||||||
res.status(200).send(data)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
router.get(
|
|
||||||
'/servers/:serverId/players/:playerId/weapons:weaponId',
|
|
||||||
param(['serverId', 'playerId, weaponId']).exists().toInt().isInt(),
|
|
||||||
validateErrors,
|
|
||||||
async (req, res) => {
|
|
||||||
const data = getWeaponReport(
|
|
||||||
req.params.weaponId,
|
|
||||||
Number(req.params.serverId),
|
|
||||||
Number(req.params.playerId)
|
|
||||||
)
|
|
||||||
res.status(200).send(data)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
router.use(
|
|
||||||
'/servers/:serverId/weapons',
|
|
||||||
param(['serverId']).exists().toInt().isInt(),
|
|
||||||
validateErrors,
|
|
||||||
async (req, res) => {
|
|
||||||
const data = JSON.parse((await getWeaponList(req.params.serverId)) || '{}')
|
|
||||||
res.status(200).send(data)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
router.use(
|
|
||||||
'/servers/:serverId/weapons',
|
|
||||||
param(['serverId']).exists().toInt().isInt(),
|
|
||||||
validateErrors,
|
|
||||||
async (req, res) => {
|
|
||||||
const data = getWeaponReport(
|
|
||||||
req.params.weaponId,
|
|
||||||
Number(req.params.serverId)
|
|
||||||
)
|
|
||||||
res.status(200).send(data)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|||||||
+142
-35
@@ -2,12 +2,17 @@ import db from '../db/db'
|
|||||||
import cache from '../cache/redis'
|
import cache from '../cache/redis'
|
||||||
import { processServerPlayers } from './routes/serverPlayers'
|
import { processServerPlayers } from './routes/serverPlayers'
|
||||||
/*import { processPlayerWeapons } from './routes/serverPlayerWeapons'*/
|
/*import { processPlayerWeapons } from './routes/serverPlayerWeapons'*/
|
||||||
import { processPlayerReport } from './routes/player'
|
|
||||||
import {
|
import {
|
||||||
processWeaponReport,
|
processWeaponReport,
|
||||||
populateWeaponSet,
|
populateWeaponSet,
|
||||||
processWeaponList
|
processWeaponList
|
||||||
} from './process/processWeapon'
|
} from './process/processWeapon'
|
||||||
|
import {
|
||||||
|
populatePlayerSet,
|
||||||
|
processPlayerList,
|
||||||
|
processPlayerReport
|
||||||
|
} from './process/processPlayer'
|
||||||
|
import { getWeaponSet, getPlayerSet } from '../cache/cacheUtils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the process of populating the REDIS database globally
|
* Starts the process of populating the REDIS database globally
|
||||||
@@ -16,24 +21,29 @@ import {
|
|||||||
async function processAll() {
|
async function processAll() {
|
||||||
console.log('Starting data calculation...')
|
console.log('Starting data calculation...')
|
||||||
const timeStart = new Date()
|
const timeStart = new Date()
|
||||||
|
|
||||||
// Iterate through all servers
|
// Iterate through all servers
|
||||||
const servers = await db.selectFrom('server').selectAll().execute()
|
const servers = await db.selectFrom('server').selectAll().execute()
|
||||||
|
await populateAllSets()
|
||||||
const promises: Promise<any>[] = []
|
const promises: Promise<any>[] = []
|
||||||
servers.forEach((server) => {
|
servers.forEach((server) => {
|
||||||
promises.push(processServer(server.id))
|
promises.push(processServer(server.id))
|
||||||
})
|
})
|
||||||
|
|
||||||
//Iterate through all weapons
|
//Iterate through all weapons
|
||||||
await populateWeaponSet()
|
const weapons = await getWeaponSet()
|
||||||
const weapons = await cache.SMEMBERS('weapons')
|
|
||||||
weapons.forEach((weapon) => {
|
weapons.forEach((weapon) => {
|
||||||
promises.push(processWeaponReport(weapon))
|
promises.push(processWeapon(weapon))
|
||||||
})
|
})
|
||||||
|
//Iterate through all players
|
||||||
|
|
||||||
|
const players = await getPlayerSet()
|
||||||
|
players.forEach((player) => {
|
||||||
|
promises.push(processPlayer(player))
|
||||||
|
})
|
||||||
|
|
||||||
await Promise.all(promises)
|
await Promise.all(promises)
|
||||||
await processWeaponList()
|
//Generate lists now that we have all data
|
||||||
|
await processAllLists()
|
||||||
|
|
||||||
//TODO : iterate through all players
|
|
||||||
console.log(
|
console.log(
|
||||||
'Data calculation finished. Took + ' +
|
'Data calculation finished. Took + ' +
|
||||||
Math.abs(new Date().getTime() - timeStart.getTime()) / 1000 +
|
Math.abs(new Date().getTime() - timeStart.getTime()) / 1000 +
|
||||||
@@ -46,11 +56,11 @@ async function processAll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the process of populating the REDIS database for server-related things
|
* Populte redis of server lists and reports
|
||||||
* @param server
|
* @param server
|
||||||
*/
|
*/
|
||||||
async function processServer(server: number) {
|
async function processServer(server: number) {
|
||||||
const promises: Promise<any>[] = []
|
/*const promises: Promise<any>[] = []
|
||||||
//TODO TO REMOVE OR RENAME
|
//TODO TO REMOVE OR RENAME
|
||||||
await processServerPlayers(server)
|
await processServerPlayers(server)
|
||||||
|
|
||||||
@@ -64,41 +74,138 @@ async function processServer(server: number) {
|
|||||||
//Iterate through all players present on this server (and do more stuff on those players)
|
//Iterate through all players present on this server (and do more stuff on those players)
|
||||||
const players = await cache.SMEMBERS(`servers:${server}:players`)
|
const players = await cache.SMEMBERS(`servers:${server}:players`)
|
||||||
players.forEach((player) => {
|
players.forEach((player) => {
|
||||||
promises.push(processPlayer({ server, player: Number(player) }))
|
promises.push(processPlayer({ server, player }))
|
||||||
})
|
})
|
||||||
await Promise.all(promises)
|
await Promise.all(promises)
|
||||||
await processWeaponList(server)
|
await processWeaponList(server)*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the process of populating the REDIS database for player-related things
|
* Populate redis of player lists and reports
|
||||||
* @param param0
|
* @param param0
|
||||||
*/
|
*/
|
||||||
async function processPlayer({
|
async function processPlayer(player: string) {
|
||||||
server,
|
|
||||||
player
|
|
||||||
}: {
|
|
||||||
server?: number
|
|
||||||
player: number
|
|
||||||
}) {
|
|
||||||
const serverPrefix = server ? `servers:${server}:` : ''
|
|
||||||
const playerPrefix = player ? `players:${player}:` : ''
|
|
||||||
const cacheLocation = serverPrefix + playerPrefix + `weapons`
|
|
||||||
|
|
||||||
const promises: Promise<any>[] = []
|
const promises: Promise<any>[] = []
|
||||||
//Iterate through all weapons for this player
|
//iterate through all servers
|
||||||
await populateWeaponSet(server, player)
|
const servers = await db.selectFrom('server').selectAll().execute()
|
||||||
const weapons = await cache.SMEMBERS(cacheLocation)
|
servers.forEach((server) => {
|
||||||
weapons.forEach((weapon) => {
|
promises.push(
|
||||||
promises.push(processWeaponReport(weapon, server, player))
|
processPlayerReport(player, server.id),
|
||||||
|
//Iterate through all players on servers
|
||||||
|
getWeaponSet(server.id, player).then((weapons) => {
|
||||||
|
weapons.forEach((weapon) => {
|
||||||
|
promises.push(processPlayerReport(player, server.id, weapon))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
})
|
})
|
||||||
await Promise.all(promises)
|
//iterate through all weapons outside of servers
|
||||||
await processWeaponList(server, player)
|
const weapons = await getWeaponSet(undefined, player)
|
||||||
//TODO : more data analytics
|
weapons.forEach((weapon) => {
|
||||||
/*
|
promises.push(processPlayerReport(player, undefined, weapon))
|
||||||
promises.push(processPlayerWeapons(server, player))
|
})
|
||||||
promises.push(processPlayerReport(server, player))*/
|
//global weapon data
|
||||||
|
promises.push(processPlayerReport(player))
|
||||||
await Promise.all(promises)
|
await Promise.all(promises)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function processWeapon(weapon: string) {
|
||||||
|
const promises: Promise<any>[] = []
|
||||||
|
//iterate through all servers
|
||||||
|
const servers = await db.selectFrom('server').selectAll().execute()
|
||||||
|
servers.forEach((server) => {
|
||||||
|
promises.push(
|
||||||
|
processWeaponReport(weapon, server.id),
|
||||||
|
//Iterate through all players on servers
|
||||||
|
getPlayerSet(server.id, weapon).then((players) => {
|
||||||
|
players.forEach((player) => {
|
||||||
|
promises.push(processWeaponReport(weapon, server.id, player))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
//iterate through all players outside of servers
|
||||||
|
const players = await getPlayerSet(undefined, weapon)
|
||||||
|
players.forEach((player) => {
|
||||||
|
promises.push(processWeaponReport(weapon, undefined, player))
|
||||||
|
})
|
||||||
|
//global weapon data
|
||||||
|
promises.push(processWeaponReport(weapon))
|
||||||
|
await Promise.all(promises)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function populateAllSets() {
|
||||||
|
const servers = await db.selectFrom('server').selectAll().execute()
|
||||||
|
await Promise.all([populatePlayerSet(), populateWeaponSet()])
|
||||||
|
await (async () => {
|
||||||
|
const promises: Promise<any>[] = []
|
||||||
|
await getWeaponSet().then((weaponSet) => {
|
||||||
|
weaponSet.forEach((weapon: string) => {
|
||||||
|
promises.push(populatePlayerSet(undefined, weapon))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
await getPlayerSet().then((playerSet) => {
|
||||||
|
playerSet.forEach((player) => {
|
||||||
|
promises.push(populateWeaponSet(undefined, player))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return Promise.all(promises)
|
||||||
|
})()
|
||||||
|
|
||||||
|
await (async () => {
|
||||||
|
const promises: Promise<any>[] = servers.map((server) =>
|
||||||
|
(async () => {
|
||||||
|
await Promise.all([
|
||||||
|
populatePlayerSet(server.id),
|
||||||
|
populateWeaponSet(server.id)
|
||||||
|
])
|
||||||
|
const promises: Promise<any>[] = []
|
||||||
|
await getWeaponSet(server.id).then((weaponSet) => {
|
||||||
|
weaponSet.forEach((weapon: string) => {
|
||||||
|
promises.push(populatePlayerSet(server.id, weapon))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
await getPlayerSet(server.id).then((playerSet) => {
|
||||||
|
playerSet.forEach((player) => {
|
||||||
|
promises.push(populateWeaponSet(server.id, player))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return Promise.all(promises)
|
||||||
|
})()
|
||||||
|
)
|
||||||
|
await Promise.all(promises)
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processAllLists() {
|
||||||
|
const promises: Promise<any>[] = []
|
||||||
|
promises.push(processPlayerList(), processWeaponList())
|
||||||
|
promises.push(
|
||||||
|
...(await getPlayerSet()).map((player) =>
|
||||||
|
processWeaponList(undefined, player)
|
||||||
|
),
|
||||||
|
...(await (
|
||||||
|
await getWeaponSet()
|
||||||
|
).map((weapon) => processPlayerList(undefined, weapon)))
|
||||||
|
)
|
||||||
|
const servers = await db.selectFrom('server').selectAll().execute()
|
||||||
|
promises.push(
|
||||||
|
...servers.map(async ({ id }) => {
|
||||||
|
const promises: Promise<any>[] = []
|
||||||
|
promises.push(
|
||||||
|
processWeaponList(id),
|
||||||
|
processPlayerList(id),
|
||||||
|
...(await getPlayerSet()).map((player) =>
|
||||||
|
processWeaponList(id, player)
|
||||||
|
),
|
||||||
|
...(await (
|
||||||
|
await getWeaponSet()
|
||||||
|
).map((weapon) => processPlayerList(id, weapon)))
|
||||||
|
)
|
||||||
|
await Promise.all(promises)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
await Promise.all(promises)
|
||||||
|
}
|
||||||
export default processAll
|
export default processAll
|
||||||
|
|||||||
@@ -0,0 +1,189 @@
|
|||||||
|
/**
|
||||||
|
* This file contains all functions related to population of the REDIS database for players.
|
||||||
|
*/
|
||||||
|
import db from '../../db/db'
|
||||||
|
import cache from '../../cache/redis'
|
||||||
|
import { getPlayerReport, getPlayerSet } from '../../cache/cacheUtils'
|
||||||
|
const { count, max, avg, sum } = db.fn
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the set of players (just a list with player IDS)
|
||||||
|
*
|
||||||
|
* Inputs `POSTGRESQL`
|
||||||
|
*
|
||||||
|
* Outputs `SET` `[servers:{serverId}:][weapons:{weaponId}:]players`
|
||||||
|
* @param server optional server filter
|
||||||
|
* @param weapon optional weapon filter
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function populatePlayerSet(server?: number, weapon?: string) {
|
||||||
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
|
const weaponPrefix = weapon ? `weapons:${weapon}:` : ''
|
||||||
|
const cacheLocation = serverPrefix + weaponPrefix + `players`
|
||||||
|
const last_entry = Number(await cache.GET(cacheLocation + ':last_entry')) || 0
|
||||||
|
let query = db
|
||||||
|
.selectFrom('kill')
|
||||||
|
.select([
|
||||||
|
'attacker_id',
|
||||||
|
db
|
||||||
|
.selectFrom('kill')
|
||||||
|
.select(max('kill.id').as('last_entry'))
|
||||||
|
.as('last_entry')
|
||||||
|
])
|
||||||
|
.groupBy('attacker_id')
|
||||||
|
.where('kill.id', '>', last_entry)
|
||||||
|
if (server) {
|
||||||
|
query = query.where('server', '=', server)
|
||||||
|
}
|
||||||
|
if (weapon) {
|
||||||
|
query = query.where('cause_of_death', '=', weapon)
|
||||||
|
}
|
||||||
|
const newData = await query.execute()
|
||||||
|
if (newData.length == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const promises: Promise<any>[] = []
|
||||||
|
newData.forEach(({ attacker_id }) => {
|
||||||
|
if (attacker_id == 'last_entry' || attacker_id == 'processedList') {
|
||||||
|
console.error('attacker_id cannot be ' + attacker_id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
promises.push(cache.SADD(cacheLocation, attacker_id))
|
||||||
|
})
|
||||||
|
promises.push(cache.SET(cacheLocation + ':last_entry', newData[0].last_entry))
|
||||||
|
await Promise.all(promises)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes player kills with optional server and/or weapon filter.
|
||||||
|
* Does not processes deaths from weapons.
|
||||||
|
*
|
||||||
|
* Inputs `POSTGRESQL`
|
||||||
|
*
|
||||||
|
* Outputs `HASH` `[servers:{serverId}:][weapon:{weaponId}:]players:{playerId}`
|
||||||
|
* @param player weapon to generate the report for
|
||||||
|
* @param server optional server filter
|
||||||
|
* @param weapon optional player filter
|
||||||
|
*/
|
||||||
|
|
||||||
|
export async function processPlayerReport(
|
||||||
|
player: string,
|
||||||
|
server?: number,
|
||||||
|
weapon?: string
|
||||||
|
) {
|
||||||
|
if (player == 'last_entry' || player == 'processedList') {
|
||||||
|
console.error('Player cannot be ' + player)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
|
const weaponPrefix = weapon ? `weapons:${weapon}:` : ''
|
||||||
|
const cacheLocation = serverPrefix + weaponPrefix + `players:` + player
|
||||||
|
const last_entry = Number(await cache.HGET(cacheLocation, 'last_entry')) || 0
|
||||||
|
let query = db
|
||||||
|
.selectFrom('kill')
|
||||||
|
.select([
|
||||||
|
count<number>('id')
|
||||||
|
.filterWhere('attacker_id', '=', player)
|
||||||
|
.filterWhereRef('attacker_id', '!=', 'victim_id')
|
||||||
|
.as('kills'),
|
||||||
|
count<number>('id').filterWhere('victim_id', '=', player).as('deaths'),
|
||||||
|
avg<number>('kill.distance')
|
||||||
|
.filterWhere('attacker_id', '=', player)
|
||||||
|
.as('avg_kill_distance'),
|
||||||
|
max('kill.distance')
|
||||||
|
.filterWhere('attacker_id', '=', player)
|
||||||
|
.as('max_kill_distance'),
|
||||||
|
db
|
||||||
|
.selectFrom('kill')
|
||||||
|
.select(max('kill.id').as('last_entry'))
|
||||||
|
.as('last_entry')
|
||||||
|
])
|
||||||
|
.where((qb) =>
|
||||||
|
qb.where('attacker_id', '=', player).orWhere('victim_id', '=', player)
|
||||||
|
)
|
||||||
|
.where('kill.id', '>', last_entry)
|
||||||
|
if (server) {
|
||||||
|
query = query.where('server', '=', server)
|
||||||
|
}
|
||||||
|
if (weapon) {
|
||||||
|
query = query.where('cause_of_death', '=', weapon)
|
||||||
|
}
|
||||||
|
const newData = await query.execute()
|
||||||
|
if (newData.length == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const promises: Promise<any>[] = []
|
||||||
|
newData.forEach(({ kills, avg_kill_distance, max_kill_distance, deaths }) => {
|
||||||
|
promises.push(
|
||||||
|
processAvg(cacheLocation, 'avg_kill_distance', {
|
||||||
|
newkills: kills || 0,
|
||||||
|
newavg: avg_kill_distance || 0
|
||||||
|
}).then((e) => cache.HINCRBY(cacheLocation, 'kills', kills || 0)),
|
||||||
|
cache.HINCRBY(cacheLocation, 'deaths', deaths || 0),
|
||||||
|
processMax(cacheLocation, 'max_kill_distance', max_kill_distance)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
promises.push(cache.HSET(cacheLocation, 'last_entry', newData[0].last_entry))
|
||||||
|
await Promise.all(promises)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processAvg(
|
||||||
|
cacheLocation: string,
|
||||||
|
key: 'avg_kill_distance',
|
||||||
|
{ newkills, newavg }: { newkills: number; newavg: number }
|
||||||
|
) {
|
||||||
|
const oldKills = Number(await cache.HGET(cacheLocation, 'kills')) || 0
|
||||||
|
const oldaverage = Number(await cache.HGET(cacheLocation, key)) || 0
|
||||||
|
const totalkills = Number(oldKills) + Number(newkills)
|
||||||
|
const newAverage =
|
||||||
|
(oldKills / totalkills) * oldaverage + (newkills / totalkills) * newavg || 0
|
||||||
|
await cache.HSET(cacheLocation, key, newAverage)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processMax(
|
||||||
|
cacheLocation: string,
|
||||||
|
key: 'max_kill_distance',
|
||||||
|
newmax: number
|
||||||
|
) {
|
||||||
|
const oldMax = Number(await cache.HGET(cacheLocation, key)) || 0
|
||||||
|
if (oldMax < newmax || oldMax == 0)
|
||||||
|
await cache.HSET(cacheLocation, key, newmax || 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines player reports in a readable json string.
|
||||||
|
*
|
||||||
|
* ProcessPlayerReport must be called manually before this function !
|
||||||
|
*
|
||||||
|
* Inputs `SET` `[servers:{serverId}:][weapons:{weaponId}:]players`
|
||||||
|
*
|
||||||
|
* Outputs `STRING` `[servers:{serverId}:][weapons:{weaponId}:]players:processedList`
|
||||||
|
* @param server optional server filter
|
||||||
|
* @param weapon optional player filter
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function processPlayerList(server?: number, weapon?: string) {
|
||||||
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
|
const weaponPrefix = weapon ? `weapons:${weapon}:` : ''
|
||||||
|
const cacheLocation = serverPrefix + weaponPrefix + `players`
|
||||||
|
const players = await getPlayerSet(server, weapon)
|
||||||
|
const promises: Promise<any>[] = []
|
||||||
|
const data: {
|
||||||
|
[playerId: string]: {
|
||||||
|
[playerData: string]: string
|
||||||
|
}
|
||||||
|
} = {}
|
||||||
|
players.forEach((plr) => {
|
||||||
|
promises.push(
|
||||||
|
(async () => {
|
||||||
|
const playerData = await getPlayerReport(plr, server, weapon)
|
||||||
|
if (Object.keys(playerData).length > 0) {
|
||||||
|
data[plr] = playerData
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
)
|
||||||
|
})
|
||||||
|
await Promise.all(promises)
|
||||||
|
return await cache.SET(cacheLocation + `:processedList`, JSON.stringify(data))
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ const { count, max, avg } = db.fn
|
|||||||
* @param player optional player filter
|
* @param player optional player filter
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export async function populateWeaponSet(server?: number, player?: number) {
|
export async function populateWeaponSet(server?: number, player?: string) {
|
||||||
const serverPrefix = server ? `servers:${server}:` : ''
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
const playerPrefix = player ? `players:${player}:` : ''
|
const playerPrefix = player ? `players:${player}:` : ''
|
||||||
const cacheLocation = serverPrefix + playerPrefix + `weapons`
|
const cacheLocation = serverPrefix + playerPrefix + `weapons`
|
||||||
@@ -37,8 +37,8 @@ export async function populateWeaponSet(server?: number, player?: number) {
|
|||||||
}
|
}
|
||||||
if (player) {
|
if (player) {
|
||||||
query = query
|
query = query
|
||||||
.where('attacker_id', '=', player.toString())
|
.where('attacker_id', '=', player)
|
||||||
.orWhere('victim_id', '=', player.toString())
|
.orWhere('victim_id', '=', player)
|
||||||
}
|
}
|
||||||
const newData = await query.execute()
|
const newData = await query.execute()
|
||||||
if (newData.length == 0) {
|
if (newData.length == 0) {
|
||||||
@@ -71,7 +71,7 @@ export async function populateWeaponSet(server?: number, player?: number) {
|
|||||||
export async function processWeaponReport(
|
export async function processWeaponReport(
|
||||||
weapon: string,
|
weapon: string,
|
||||||
server?: number,
|
server?: number,
|
||||||
player?: number
|
player?: string
|
||||||
) {
|
) {
|
||||||
if (weapon == 'last_entry' || weapon == 'processedList') {
|
if (weapon == 'last_entry' || weapon == 'processedList') {
|
||||||
console.error('Weapon cannot be ' + weapon)
|
console.error('Weapon cannot be ' + weapon)
|
||||||
@@ -93,15 +93,17 @@ export async function processWeaponReport(
|
|||||||
.as('last_entry')
|
.as('last_entry')
|
||||||
])
|
])
|
||||||
.where('cause_of_death', '=', weapon)
|
.where('cause_of_death', '=', weapon)
|
||||||
|
.whereRef('attacker_id', '!=', 'victim_id')
|
||||||
.where('kill.id', '>', last_entry)
|
.where('kill.id', '>', last_entry)
|
||||||
.groupBy('cause_of_death')
|
.groupBy('cause_of_death')
|
||||||
if (server) {
|
if (server) {
|
||||||
query = query.where('server', '=', server)
|
query = query.where('server', '=', server)
|
||||||
}
|
}
|
||||||
if (player) {
|
if (player) {
|
||||||
query = query.where('attacker_id', '=', player.toString())
|
query = query.where('attacker_id', '=', player)
|
||||||
}
|
}
|
||||||
const newData = await query.execute()
|
const newData = await query.execute()
|
||||||
|
|
||||||
if (newData.length == 0) {
|
if (newData.length == 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -137,7 +139,9 @@ async function processMax(
|
|||||||
key: 'max_kill_distance',
|
key: 'max_kill_distance',
|
||||||
newmax: number
|
newmax: number
|
||||||
) {
|
) {
|
||||||
const oldMax = Number(await cache.HGET(cacheLocation, key)) | 0
|
const oldMax = Number(await cache.HGET(cacheLocation, key)) || -1
|
||||||
|
newmax = newmax || 0
|
||||||
|
if (!oldMax || !newmax) console.log(oldMax, newmax)
|
||||||
if (oldMax < newmax) await cache.HSET(cacheLocation, key, newmax)
|
if (oldMax < newmax) await cache.HSET(cacheLocation, key, newmax)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,10 +157,11 @@ async function processMax(
|
|||||||
* @param player optional player filter
|
* @param player optional player filter
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export async function processWeaponList(server?: number, player?: number) {
|
export async function processWeaponList(server?: number, player?: string) {
|
||||||
const serverPrefix = server ? `servers:${server}:` : ''
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
const playerPrefix = player ? `players:${player}:` : ''
|
const playerPrefix = player ? `players:${player}:` : ''
|
||||||
const weapons = await cache.SMEMBERS('weapons')
|
const cacheLocation = serverPrefix + playerPrefix + `weapons`
|
||||||
|
const weapons = await cache.SMEMBERS(cacheLocation)
|
||||||
const promises: Promise<any>[] = []
|
const promises: Promise<any>[] = []
|
||||||
const data: {
|
const data: {
|
||||||
[weaponId: string]: {
|
[weaponId: string]: {
|
||||||
@@ -174,8 +179,5 @@ export async function processWeaponList(server?: number, player?: number) {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
await Promise.all(promises)
|
await Promise.all(promises)
|
||||||
return await cache.SET(
|
return await cache.SET(cacheLocation + `:processedList`, JSON.stringify(data))
|
||||||
serverPrefix + playerPrefix + `weapons:processedList`,
|
|
||||||
JSON.stringify(data)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-12
@@ -2,7 +2,8 @@ import { RequestHandler } from 'express'
|
|||||||
import { param } from 'express-validator'
|
import { param } from 'express-validator'
|
||||||
import { validateErrors } from '../../common'
|
import { validateErrors } from '../../common'
|
||||||
import cache from '../../cache/redis'
|
import cache from '../../cache/redis'
|
||||||
import { sql } from 'kysely'
|
import { getWeaponList, getPlayerReport } from '../../cache/cacheUtils'
|
||||||
|
import { DataTypeNode, sql } from 'kysely'
|
||||||
import db from '../../db/db'
|
import db from '../../db/db'
|
||||||
//import { getPlayerWeapons } from './serverPlayerWeapons'
|
//import { getPlayerWeapons } from './serverPlayerWeapons'
|
||||||
|
|
||||||
@@ -13,22 +14,20 @@ const middlewares: RequestHandler[] = [
|
|||||||
param(['serverId', 'playerId']).exists().toInt().isInt(),
|
param(['serverId', 'playerId']).exists().toInt().isInt(),
|
||||||
validateErrors,
|
validateErrors,
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const server = Number(req.params.serverId)
|
|
||||||
const player = Number(req.params.playerId)
|
|
||||||
//await processPlayerReport(server, player)
|
//await processPlayerReport(server, player)
|
||||||
const data = await getPlayerReport(server, player)
|
const data = await getPlayerReport(
|
||||||
//const weapons = await getPlayerWeapons(server, player)
|
req.params.playerId,
|
||||||
|
Number(req.params.serverId)
|
||||||
|
)
|
||||||
|
const weapons = await getWeaponList(
|
||||||
|
req.params.serverId,
|
||||||
|
req.params.playerId
|
||||||
|
)
|
||||||
|
data.weapons = weapons
|
||||||
res.status(200).send(data)
|
res.status(200).send(data)
|
||||||
//res.status(200).send({ ...data, weapons })
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
async function getPlayerReport(server: number, player: number) {
|
|
||||||
const data = await cache.HGETALL(`servers:${server}:players:${player}`)
|
|
||||||
delete data.last_entry
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function processPlayerReport(server: number, player: number) {
|
export async function processPlayerReport(server: number, player: number) {
|
||||||
let last_entry =
|
let last_entry =
|
||||||
Number(
|
Number(
|
||||||
|
|||||||
+2
-1
@@ -10,7 +10,8 @@ const db = new Kysely<Database>({
|
|||||||
host: process.env.POSTGRES_HOST,
|
host: process.env.POSTGRES_HOST,
|
||||||
database: process.env.POSTGRES_DATABASE,
|
database: process.env.POSTGRES_DATABASE,
|
||||||
user: process.env.POSTGRES_USER,
|
user: process.env.POSTGRES_USER,
|
||||||
password: process.env.POSTGRES_PASSWORD
|
password: process.env.POSTGRES_PASSWORD,
|
||||||
|
max: 30
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
log(event) {
|
log(event) {
|
||||||
|
|||||||
Reference in New Issue
Block a user