optimize sql function for v2
This commit is contained in:
+183
-164
@@ -1,15 +1,8 @@
|
|||||||
import db from '../db/db'
|
import db from '../db/db'
|
||||||
import {
|
const { count, max, sum } = db.fn
|
||||||
processWeaponReport,
|
import client from '../cache/redis'
|
||||||
populateWeaponSet,
|
import { createWeaponJson } from './process/processWeapon'
|
||||||
processWeaponList
|
import { createPlayerJson } from './process/processPlayer'
|
||||||
} 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
|
||||||
@@ -18,29 +11,8 @@ import { getWeaponSet, getPlayerSet } from '../cache/cacheUtils'
|
|||||||
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
|
|
||||||
const servers = await db.selectFrom('server').selectAll().execute()
|
|
||||||
await populateAllSets()
|
|
||||||
const promises: Promise<any>[] = []
|
|
||||||
servers.forEach((server) => {
|
|
||||||
promises.push(processServer(server.id))
|
|
||||||
})
|
|
||||||
//Iterate through all weapons
|
|
||||||
const weapons = await getWeaponSet()
|
|
||||||
weapons.forEach((weapon) => {
|
|
||||||
promises.push(processWeapon(weapon))
|
|
||||||
})
|
|
||||||
//Iterate through all players
|
|
||||||
|
|
||||||
const players = await getPlayerSet()
|
|
||||||
players.forEach((player) => {
|
|
||||||
promises.push(processPlayer(player))
|
|
||||||
})
|
|
||||||
|
|
||||||
await Promise.all(promises)
|
|
||||||
//Generate lists now that we have all data
|
|
||||||
await processAllLists()
|
|
||||||
|
|
||||||
|
await Promise.all([processGlobalStats(), processServerStats()])
|
||||||
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 +
|
||||||
@@ -52,157 +24,204 @@ async function processAll() {
|
|||||||
setTimeout(processAll, 3600000)
|
setTimeout(processAll, 3600000)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async function processGlobalStats() {
|
||||||
* Populte redis of server lists and reports
|
let promises: Promise<any>[] = []
|
||||||
* @param server
|
//Global kills
|
||||||
*/
|
promises.push(db.selectFrom('kill')
|
||||||
async function processServer(server: number) {
|
.select([count('id').as('kills'), max('distance').as('max_distance'), sum('distance').as('total_distance')])
|
||||||
/*const promises: Promise<any>[] = []
|
.execute().then(data => {
|
||||||
//TODO TO REMOVE OR RENAME
|
let transaction = client.multi()
|
||||||
await processServerPlayers(server)
|
data.forEach(({ kills, max_distance, total_distance }) => {
|
||||||
|
transaction = processGlobalData({ kills, max_distance, total_distance }, transaction)
|
||||||
//Iterate through all weapons present on this server
|
|
||||||
await populateWeaponSet(server)
|
|
||||||
const weapons = await cache.SMEMBERS(`servers:${server}:weapons`)
|
|
||||||
weapons.forEach((weapon) => {
|
|
||||||
promises.push(processWeaponReport(weapon, server))
|
|
||||||
})
|
})
|
||||||
|
return transaction.exec()
|
||||||
|
}))
|
||||||
|
|
||||||
//Iterate through all players present on this server (and do more stuff on those players)
|
//Global weapon kill
|
||||||
const players = await cache.SMEMBERS(`servers:${server}:players`)
|
promises.push(db.selectFrom('kill')
|
||||||
players.forEach((player) => {
|
.select([count('id').as('kills'), max('distance').as('max_distance'), sum('distance').as('total_distance'), 'cause_of_death'])
|
||||||
promises.push(processPlayer({ server, player }))
|
.groupBy('cause_of_death').execute().then(async (data) => {
|
||||||
|
let transaction = client.multi()
|
||||||
|
data.forEach(({ kills, max_distance, total_distance, cause_of_death }) => {
|
||||||
|
transaction = processWeaponData({ kills, max_distance, total_distance, cause_of_death }, transaction)
|
||||||
})
|
})
|
||||||
await Promise.all(promises)
|
await transaction.exec()
|
||||||
await processWeaponList(server)*/
|
}))
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
//Player weapon kills
|
||||||
* Populate redis of player lists and reports
|
promises.push(db.selectFrom('kill')
|
||||||
* @param param0
|
.select([count('id').as('kills'), max('distance').as('max_distance'), sum('distance').as('total_distance'), 'cause_of_death', 'attacker_id'])
|
||||||
*/
|
.groupBy(['cause_of_death', 'attacker_id']).execute().then(async (data) => {
|
||||||
async function processPlayer(player: string) {
|
let transaction = client.multi()
|
||||||
const promises: Promise<any>[] = []
|
data.forEach(({ kills, max_distance, total_distance, cause_of_death, attacker_id }) => {
|
||||||
//iterate through all servers
|
transaction = processWeaponData({ kills, max_distance, total_distance, cause_of_death, attacker_id }, transaction)
|
||||||
const servers = await db.selectFrom('server').selectAll().execute()
|
|
||||||
servers.forEach((server) => {
|
|
||||||
promises.push(
|
|
||||||
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 transaction.exec()
|
||||||
|
}))
|
||||||
|
//Player weapon deaths
|
||||||
|
promises.push(db.selectFrom('kill').select([count('id').as('deaths'), 'victim_id', 'cause_of_death'])
|
||||||
|
.groupBy(['victim_id', 'cause_of_death']).execute().then(data => {
|
||||||
|
let transaction = client.multi()
|
||||||
|
data.forEach(({ deaths, victim_id, cause_of_death }) => {
|
||||||
|
transaction = transaction.HSET(`weapons:${cause_of_death}:players:${victim_id}`, "deaths", deaths.toString())
|
||||||
|
})
|
||||||
|
return transaction.exec()
|
||||||
|
}))
|
||||||
|
|
||||||
|
//Global player kills
|
||||||
|
promises.push(db.selectFrom('kill')
|
||||||
|
.select([count('id').as('kills'), max('distance').as('max_distance'), sum('distance').as('total_distance'), 'attacker_id'])
|
||||||
|
.groupBy('attacker_id').execute().then(data => {
|
||||||
|
let transaction = client.multi()
|
||||||
|
data.forEach(({ kills, max_distance, total_distance, attacker_id }) => {
|
||||||
|
processPlayerData({ kills, max_distance, total_distance, attacker_id }, transaction)
|
||||||
|
})
|
||||||
|
return transaction.exec()
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
//Global player deaths
|
||||||
|
promises.push(db.selectFrom('kill').select([count('id').as('deaths'), 'victim_id'])
|
||||||
|
.groupBy('victim_id').execute().then(data => {
|
||||||
|
let transaction = client.multi()
|
||||||
|
data.forEach(({ deaths, victim_id }) => {
|
||||||
|
transaction = transaction.HSET('players:' + victim_id, "deaths", deaths.toString())
|
||||||
})
|
})
|
||||||
//iterate through all weapons outside of servers
|
return transaction.exec()
|
||||||
const weapons = await getWeaponSet(undefined, player)
|
}))
|
||||||
weapons.forEach((weapon) => {
|
|
||||||
promises.push(processPlayerReport(player, undefined, weapon))
|
await Promise.all(promises)
|
||||||
})
|
promises = [];
|
||||||
//global weapon data
|
promises.push(createWeaponJson());
|
||||||
promises.push(processPlayerReport(player))
|
promises.push(createPlayerJson());
|
||||||
|
(await client.sMembers('players')).forEach((player: string) => {
|
||||||
|
promises.push(createWeaponJson(undefined, player))
|
||||||
|
});
|
||||||
|
(await client.sMembers('weapons')).forEach((weapon: string) => {
|
||||||
|
promises.push(createPlayerJson(undefined, weapon))
|
||||||
|
});
|
||||||
await Promise.all(promises)
|
await Promise.all(promises)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processWeapon(weapon: string) {
|
async function processServerStats() {
|
||||||
const promises: Promise<any>[] = []
|
let promises: Promise<any>[] = []
|
||||||
//iterate through all servers
|
//Server global kills
|
||||||
const servers = await db.selectFrom('server').selectAll().execute()
|
promises.push(db.selectFrom('kill')
|
||||||
servers.forEach((server) => {
|
.select([count('id').as('kills'), max('distance').as('max_distance'), sum('distance').as('total_distance'), 'server'])
|
||||||
promises.push(
|
.groupBy(['server']).execute().then(data => {
|
||||||
processWeaponReport(weapon, server.id),
|
let transaction = client.multi()
|
||||||
//Iterate through all players on servers
|
data.forEach(({ kills, max_distance, total_distance, server }) => {
|
||||||
getPlayerSet(server.id, weapon).then((players) => {
|
transaction = processGlobalData({ kills, max_distance, total_distance, server }, transaction)
|
||||||
players.forEach((player) => {
|
|
||||||
promises.push(processWeaponReport(weapon, server.id, player))
|
|
||||||
})
|
})
|
||||||
|
return transaction.exec()
|
||||||
|
}))
|
||||||
|
//Server weapon kills
|
||||||
|
promises.push(db.selectFrom('kill')
|
||||||
|
.select([count('id').as('kills'), max('distance').as('max_distance'), sum('distance').as('total_distance'), 'cause_of_death', 'server'])
|
||||||
|
.groupBy(['cause_of_death', 'server']).execute().then(data => {
|
||||||
|
let transaction = client.multi()
|
||||||
|
data.forEach(({ kills, max_distance, total_distance, cause_of_death, server }) => {
|
||||||
|
transaction = processWeaponData({ kills, max_distance, total_distance, cause_of_death, server }, transaction)
|
||||||
|
})
|
||||||
|
return transaction.exec()
|
||||||
|
}))
|
||||||
|
|
||||||
|
//Server Player weapon kills
|
||||||
|
promises.push(db.selectFrom('kill')
|
||||||
|
.select([count('id').as('kills'), max('distance').as('max_distance'), sum('distance').as('total_distance'), 'cause_of_death', 'attacker_id', 'server'])
|
||||||
|
.groupBy(['cause_of_death', 'attacker_id', 'server']).execute().then(data => {
|
||||||
|
let transaction = client.multi()
|
||||||
|
data.forEach(({ kills, max_distance, total_distance, cause_of_death, attacker_id, server }) => {
|
||||||
|
transaction = processWeaponData({ kills, max_distance, total_distance, cause_of_death, attacker_id, server }, transaction)
|
||||||
|
})
|
||||||
|
return transaction.exec()
|
||||||
|
}))
|
||||||
|
//Server Player weapon deaths
|
||||||
|
promises.push(db.selectFrom('kill').select([count('id').as('deaths'), 'victim_id', 'cause_of_death', 'server'])
|
||||||
|
.groupBy(['victim_id', 'cause_of_death', 'server']).execute().then(data => {
|
||||||
|
let transaction = client.multi()
|
||||||
|
data.forEach(({ deaths, victim_id, cause_of_death, server }) => {
|
||||||
|
transaction = transaction.HSET(`servers:${server}:weapons:${cause_of_death}:players:${victim_id}`, "deaths", deaths.toString())
|
||||||
|
})
|
||||||
|
return transaction.exec()
|
||||||
|
}))
|
||||||
|
|
||||||
|
//server player kills
|
||||||
|
promises.push(db.selectFrom('kill')
|
||||||
|
.select([count('id').as('kills'), max('distance').as('max_distance'), sum('distance').as('total_distance'), 'attacker_id', 'server'])
|
||||||
|
.groupBy(['attacker_id', 'server']).execute().then(data => {
|
||||||
|
let transaction = client.multi()
|
||||||
|
data.forEach(({ kills, max_distance, total_distance, attacker_id, server }) => {
|
||||||
|
transaction = processPlayerData({ kills, max_distance, total_distance, attacker_id, server }, transaction)
|
||||||
|
})
|
||||||
|
return transaction.exec()
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//server player deaths
|
||||||
|
promises.push(db.selectFrom('kill').select([count('id').as('deaths'), 'victim_id', 'server'])
|
||||||
|
.groupBy(['victim_id', 'server']).execute().then(data => {
|
||||||
|
let transaction = client.multi()
|
||||||
|
data.forEach(({ deaths, victim_id, server }) => {
|
||||||
|
transaction = transaction.HSET('servers:' + server + ':players:' + victim_id, "deaths", deaths.toString())
|
||||||
})
|
})
|
||||||
//iterate through all players outside of servers
|
return transaction.exec()
|
||||||
const players = await getPlayerSet(undefined, weapon)
|
}))
|
||||||
players.forEach((player) => {
|
|
||||||
promises.push(processWeaponReport(weapon, undefined, player))
|
await Promise.all(promises)
|
||||||
|
promises = [];
|
||||||
|
((await client.sMembers('servers')).forEach((server: string) => {
|
||||||
|
if (isNaN(Number(server))) return
|
||||||
|
promises.push(createWeaponJson(Number(server)));
|
||||||
|
promises.push(createPlayerJson(Number(server)));
|
||||||
|
promises.push(client.sMembers('servers:' + server + ':players').then(data => {
|
||||||
|
data.forEach((player: string) => {
|
||||||
|
promises.push(createWeaponJson(Number(server), player))
|
||||||
})
|
})
|
||||||
//global weapon data
|
}))
|
||||||
promises.push(processWeaponReport(weapon))
|
promises.push(client.sMembers('servers:' + server + 'weapons').then(data => {
|
||||||
|
data.forEach((weapon: string) => {
|
||||||
|
promises.push(createPlayerJson(Number(server), weapon))
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
}));
|
||||||
|
|
||||||
await Promise.all(promises)
|
await Promise.all(promises)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function populateAllSets() {
|
function processGlobalData({ kills, max_distance, total_distance, server }: { kills: string | number | bigint, max_distance: number, total_distance: string | number | bigint, server?: number }, transaction: any) {
|
||||||
const servers = await db.selectFrom('server').selectAll().execute()
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
await Promise.all([populatePlayerSet(), populateWeaponSet()])
|
const cacheLocation = serverPrefix + 'global'
|
||||||
await (async () => {
|
transaction = transaction.HSET(cacheLocation, "total_distance", total_distance.toString())
|
||||||
const promises: Promise<any>[] = []
|
transaction = transaction.HSET(cacheLocation, "max_distance", max_distance.toString())
|
||||||
await getWeaponSet().then((weaponSet) => {
|
transaction = transaction.HSET(cacheLocation, "kills", kills.toString())
|
||||||
weaponSet.forEach((weapon: string) => {
|
if (server) {
|
||||||
promises.push(populatePlayerSet(undefined, weapon))
|
transaction = transaction.SADD('servers', server.toString())
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
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() {
|
return transaction
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function processWeaponData({ kills, max_distance, total_distance, cause_of_death, attacker_id, server }: { kills: string | number | bigint, max_distance: number, total_distance: string | number | bigint, cause_of_death: string, attacker_id?: string, server?: number }, transaction: any) {
|
||||||
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
|
const playerPrefix = attacker_id ? `players:${attacker_id}:` : ''
|
||||||
|
const cacheLocation = serverPrefix + playerPrefix + `weapons:` + cause_of_death
|
||||||
|
transaction = transaction.HSET(cacheLocation, "total_distance", total_distance.toString())
|
||||||
|
transaction = transaction.HSET(cacheLocation, "max_distance", max_distance.toString())
|
||||||
|
transaction = transaction.HSET(cacheLocation, "kills", kills.toString())
|
||||||
|
transaction = transaction.SADD(serverPrefix + playerPrefix + `weapons`, cause_of_death.toString())
|
||||||
|
return transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
function processPlayerData({ kills, max_distance, total_distance, attacker_id, cause_of_death, server }: { kills: string | number | bigint, max_distance: number, total_distance: string | number | bigint, attacker_id: string, server?: number, cause_of_death?: string }, transaction: any) {
|
||||||
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
|
const weaponPrefix = cause_of_death ? `weapons:${cause_of_death}:` : ''
|
||||||
|
const cacheLocation = serverPrefix + weaponPrefix + `players:` + attacker_id
|
||||||
|
|
||||||
|
transaction = transaction.HSET(cacheLocation, "total_distance", total_distance.toString())
|
||||||
|
transaction = transaction.HSET(cacheLocation, "max_distance", max_distance.toString())
|
||||||
|
transaction = transaction.HSET(cacheLocation, "kills", kills.toString())
|
||||||
|
transaction = transaction.SADD(serverPrefix + weaponPrefix + `players`, attacker_id.toString())
|
||||||
|
return transaction
|
||||||
|
}
|
||||||
|
|
||||||
export default processAll
|
export default processAll
|
||||||
|
|||||||
@@ -1,208 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* This file contains all functions related to population of the REDIS database for players.
|
* 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 cache from '../../cache/redis'
|
||||||
import { getPlayerReport, getPlayerSet } from '../../cache/cacheUtils'
|
import { getPlayerReport, getPlayerSet } from '../../cache/cacheUtils'
|
||||||
import { sql } from 'kysely'
|
|
||||||
const { count, max, avg } = 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 = !isNaN(Number(server?.toString()))
|
|
||||||
? `servers:${server}:`
|
|
||||||
: ''
|
|
||||||
const weaponPrefix = weapon ? `weapons:${weapon}:` : ''
|
|
||||||
const cacheLocation = serverPrefix + weaponPrefix + `players`
|
|
||||||
const last_entry = Number(await cache.GET(cacheLocation + ':last_entry')) || 0
|
|
||||||
|
|
||||||
//processKills
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
let 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))
|
|
||||||
})
|
|
||||||
|
|
||||||
//processDeaths
|
|
||||||
let query2 = db
|
|
||||||
.selectFrom('kill')
|
|
||||||
.select([
|
|
||||||
sql<string>`DISTINCT(victim_id)`.as('victim_id'),
|
|
||||||
db
|
|
||||||
.selectFrom('kill')
|
|
||||||
.select(max('kill.id').as('last_entry'))
|
|
||||||
.as('last_entry')
|
|
||||||
])
|
|
||||||
.where('kill.id', '>', last_entry)
|
|
||||||
if (server) {
|
|
||||||
query2 = query2.where('server', '=', server)
|
|
||||||
}
|
|
||||||
if (weapon) {
|
|
||||||
query2 = query2.where('cause_of_death', '=', weapon)
|
|
||||||
}
|
|
||||||
const newData2 = await query2.execute()
|
|
||||||
newData2.forEach(({ victim_id }) => {
|
|
||||||
if (victim_id == 'last_entry' || victim_id == 'processedList') {
|
|
||||||
console.error('victim_id cannot be ' + victim_id)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
promises.push(cache.SADD(cacheLocation, victim_id))
|
|
||||||
})
|
|
||||||
newData = await query.execute()
|
|
||||||
promises.push(
|
|
||||||
cache.SET(cacheLocation + ':last_entry', newData2[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([
|
|
||||||
sql<string>`percentile_disc(0) WITHIN GROUP (ORDER BY attacker_name) FILTER (where attacker_id = ${player})`.as(
|
|
||||||
'username'
|
|
||||||
),
|
|
||||||
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, username }) => {
|
|
||||||
promises.push(
|
|
||||||
(async () => {
|
|
||||||
if (!username) {
|
|
||||||
await cache.HSET(
|
|
||||||
cacheLocation,
|
|
||||||
'username',
|
|
||||||
(await cache.HGET(`players:` + player, 'username')) || ''
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
await cache.HSET(cacheLocation, 'username', username)
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
)
|
|
||||||
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.
|
* Combines player reports in a readable json string.
|
||||||
@@ -216,7 +16,7 @@ async function processMax(
|
|||||||
* @param weapon optional player filter
|
* @param weapon optional player filter
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export async function processPlayerList(server?: number, weapon?: string) {
|
export async function createPlayerJson(server?: number, weapon?: string) {
|
||||||
const serverPrefix = server ? `servers:${server}:` : ''
|
const serverPrefix = server ? `servers:${server}:` : ''
|
||||||
const weaponPrefix = weapon ? `weapons:${weapon}:` : ''
|
const weaponPrefix = weapon ? `weapons:${weapon}:` : ''
|
||||||
const cacheLocation = serverPrefix + weaponPrefix + `players`
|
const cacheLocation = serverPrefix + weaponPrefix + `players`
|
||||||
|
|||||||
@@ -1,149 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* This file contains all functions related to population of the REDIS database for weapons.
|
* This file contains all functions related to population of the REDIS database for weapons.
|
||||||
*/
|
*/
|
||||||
import db from '../../db/db'
|
|
||||||
import cache from '../../cache/redis'
|
import cache from '../../cache/redis'
|
||||||
import { getWeaponReport } from '../../cache/cacheUtils'
|
import { getWeaponReport } from '../../cache/cacheUtils'
|
||||||
const { count, max, avg } = db.fn
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Populates the set of weapons (just a list with weapon names)
|
|
||||||
*
|
|
||||||
* Inputs `POSTGRESQL`
|
|
||||||
*
|
|
||||||
* Outputs `SET` `[servers:{serverId}:][players:{playerId}:]weapons`
|
|
||||||
* @param server optional server filter
|
|
||||||
* @param player optional player filter
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export async function populateWeaponSet(server?: number, player?: string) {
|
|
||||||
const serverPrefix = server ? `servers:${server}:` : ''
|
|
||||||
const playerPrefix = player ? `players:${player}:` : ''
|
|
||||||
const cacheLocation = serverPrefix + playerPrefix + `weapons`
|
|
||||||
const last_entry = Number(await cache.GET(cacheLocation + ':last_entry')) || 0
|
|
||||||
let query = db
|
|
||||||
.selectFrom('kill')
|
|
||||||
.select([
|
|
||||||
'cause_of_death',
|
|
||||||
db
|
|
||||||
.selectFrom('kill')
|
|
||||||
.select(max('kill.id').as('last_entry'))
|
|
||||||
.as('last_entry')
|
|
||||||
])
|
|
||||||
.groupBy('cause_of_death')
|
|
||||||
.where('kill.id', '>', last_entry)
|
|
||||||
if (server) {
|
|
||||||
query = query.where('server', '=', server)
|
|
||||||
}
|
|
||||||
if (player) {
|
|
||||||
query = query
|
|
||||||
.where('attacker_id', '=', player)
|
|
||||||
.orWhere('victim_id', '=', player)
|
|
||||||
}
|
|
||||||
const newData = await query.execute()
|
|
||||||
if (newData.length == 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const promises: Promise<any>[] = []
|
|
||||||
newData.forEach(({ cause_of_death }) => {
|
|
||||||
if (cause_of_death == 'last_entry' || cause_of_death == 'processedList') {
|
|
||||||
console.error('cause_of_death cannot be ' + cause_of_death)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
promises.push(cache.SADD(cacheLocation, cause_of_death))
|
|
||||||
})
|
|
||||||
promises.push(cache.SET(cacheLocation + ':last_entry', newData[0].last_entry))
|
|
||||||
await Promise.all(promises)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes weapon kills with optional server and/or player filter.
|
|
||||||
* Does not processes deaths from weapons.
|
|
||||||
*
|
|
||||||
* Inputs `POSTGRESQL`
|
|
||||||
*
|
|
||||||
* Outputs `HASH` `[servers:{serverId}:][players:{playerId}:]weapons:{weaponId}`
|
|
||||||
* @param weapon weapon to generate the report for
|
|
||||||
* @param server optional server filter
|
|
||||||
* @param player optional player filter
|
|
||||||
*/
|
|
||||||
|
|
||||||
export async function processWeaponReport(
|
|
||||||
weapon: string,
|
|
||||||
server?: number,
|
|
||||||
player?: string
|
|
||||||
) {
|
|
||||||
if (weapon == 'last_entry' || weapon == 'processedList') {
|
|
||||||
console.error('Weapon cannot be ' + weapon)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const serverPrefix = server ? `servers:${server}:` : ''
|
|
||||||
const playerPrefix = player ? `players:${player}:` : ''
|
|
||||||
const cacheLocation = serverPrefix + playerPrefix + `weapons:` + weapon
|
|
||||||
const last_entry = Number(await cache.HGET(cacheLocation, 'last_entry')) || 0
|
|
||||||
let query = db
|
|
||||||
.selectFrom('kill')
|
|
||||||
.select([
|
|
||||||
count<number>('id').as('kills'),
|
|
||||||
avg<number>('kill.distance').as('avg_kill_distance'),
|
|
||||||
max('kill.distance').as('max_kill_distance'),
|
|
||||||
db
|
|
||||||
.selectFrom('kill')
|
|
||||||
.select(max('kill.id').as('last_entry'))
|
|
||||||
.as('last_entry')
|
|
||||||
])
|
|
||||||
.where('cause_of_death', '=', weapon)
|
|
||||||
.whereRef('attacker_id', '!=', 'victim_id')
|
|
||||||
.where('kill.id', '>', last_entry)
|
|
||||||
.groupBy('cause_of_death')
|
|
||||||
if (server) {
|
|
||||||
query = query.where('server', '=', server)
|
|
||||||
}
|
|
||||||
if (player) {
|
|
||||||
query = query.where('attacker_id', '=', player)
|
|
||||||
}
|
|
||||||
const newData = await query.execute()
|
|
||||||
|
|
||||||
if (newData.length == 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const promises: Promise<any>[] = []
|
|
||||||
newData.forEach(({ kills, avg_kill_distance, max_kill_distance }) => {
|
|
||||||
promises.push(
|
|
||||||
processAvg(cacheLocation, 'avg_kill_distance', {
|
|
||||||
newkills: kills,
|
|
||||||
newavg: avg_kill_distance
|
|
||||||
}).then((e) => cache.HINCRBY(cacheLocation, 'kills', kills)),
|
|
||||||
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 = oldKills + newkills
|
|
||||||
const newAverage =
|
|
||||||
(oldKills / totalkills) * oldaverage + (newkills / totalkills) * newavg
|
|
||||||
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)) || -1
|
|
||||||
newmax = newmax || 0
|
|
||||||
if (!oldMax || !newmax) console.log(oldMax, newmax)
|
|
||||||
if (oldMax < newmax) await cache.HSET(cacheLocation, key, newmax)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combines weapons reports in a readable json string.
|
* Combines weapons reports in a readable json string.
|
||||||
@@ -157,7 +16,7 @@ async function processMax(
|
|||||||
* @param player optional player filter
|
* @param player optional player filter
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export async function processWeaponList(server?: number, player?: string) {
|
export async function createWeaponJson(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`
|
||||||
|
|||||||
Reference in New Issue
Block a user