diff --git a/.env.example b/.env.example index 8d6f21b..a738bf1 100644 --- a/.env.example +++ b/.env.example @@ -2,4 +2,5 @@ POSTGRES_HOST="localhost" POSTGRES_DATABASE="postgres" POSTGRES_USER="postgres" POSTGRES_PASSWORD="postgres" -SERVERAUTH_TOKEN="1:f9f8fc8c-9185-47a8-8a99-9e3acf6ca007" \ No newline at end of file +SERVERAUTH_TOKEN="1:f9f8fc8c-9185-47a8-8a99-9e3acf6ca007" +ENVIRONMENT='prod' \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 6ce44de..38e5052 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -10,5 +10,8 @@ module.exports = { sourceType: 'module', project: ['./tsconfig.json'] }, - rules: {} + rules: { + '@typescript-eslint/strict-boolean-expressions': 0, + '@typescript-eslint/explicit-function-return-type': 'off' + } } diff --git a/.vscode/settings.json b/.vscode/settings.json index 7ece8b5..938dad5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,11 +1,10 @@ { - "editor.codeActionsOnSave": { - "source.fixAll": true - }, "editor.formatOnSave": true, "typescript.preferences.quoteStyle": "single", "javascript.preferences.quoteStyle": "single", - "prettier.singleQuote": true, - "prettier.trailingComma": "none", - "prettier.semi": false + "editor.defaultFormatter": "dbaeumer.vscode-eslint", + "eslint.format.enable": true, + "[typescript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + } } diff --git a/src/client/client.ts b/src/client/client.ts index 0f5fdb9..096b382 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -1,149 +1,118 @@ import { Router } from 'express' -import { param, query } from 'express-validator' +import { param } from 'express-validator' import { validateErrors } from '../common' -import { allData } from '../process/process' -import { getHostList } from '../db/db' +import db, { getHostList } from '../db/db' +import { sql } from 'kysely' +const { max, sum } = db.fn const router = Router() -//timeout middleware ? +// timeout middleware ? router.get('/*', (req, res, next) => { next() }) -function computeQueryParam( - queryParam: string, - comparison: string | number -): boolean { - return queryParam.startsWith('!') - ? queryParam.substring(1) != comparison - : queryParam == comparison +const queryFilters = { + player: 'attacker_id', + server: 'servername', + map: 'map', + weapon: 'cause_of_death', + gamemode: 'game_mode', + host: 'host' +} as const + +const path = { + player: 'attacker_id', + servers: 'servername', + maps: 'map', + weapons: 'cause_of_death', + gamemodes: 'game_mode', + hosts: 'host' +} as const + +interface KillRecord { + kills: number + deaths?: number + deaths_while_equipped?: number + username?: string + max_distance: number + total_distance: number } -function filters(e: typeof allData[0], query: any) { - return ( - (query.player ? computeQueryParam(query.player, e.attacker_id) : true) && - (query.server ? computeQueryParam(query.server, e.servername) : true) && - (query.host ? computeQueryParam(query.host, e.host) : true) && - (query.map ? computeQueryParam(query.map, e.map) : true) && - (query.weapon ? computeQueryParam(query.weapon, e.cause_of_death) : true) && - (query.gamemode ? computeQueryParam(query.gamemode, e.game_mode) : true) - ) -} - -router.get('/hosts', async (req, res) => { - const result = await getHostList() - const data: { [key: number]: string } = {} - result.forEach((e) => (data[Number(e.id)] = e.name)) - res.status(200).send(data) +router.get('/hosts', (_req, res) => { + void (async () => { + const result = await getHostList() + const data: Record = {} + result.forEach((e) => (data[Number(e.id)] = e.name)) + res.status(200).send(data) + })() }) -router.get( - '/:dataType', +function processQueryArgs (data: ReturnType>, queryArgs: string | string[]): ReturnType> { + Object.entries(queryArgs).forEach(([one, two]) => { + if (!two) return + if (!(one in queryFilters)) return + const key = one as keyof typeof queryFilters + if (Array.isArray(two)) { + data = data.where((qb) => { + (two as string[]).forEach((e) => { qb = qb.orWhere(queryFilters[key], '=', e) }) + return qb + }) + } else { + data = data.where(queryFilters[key], '=', two) + } + }) + return data +} + +router.get('/players', + (req, res) => { + void (async () => { + let data = db.selectFrom('kill_view') + if (req.query) { + data = processQueryArgs(data, req.query as unknown as string | string[]) + } + const selection = data.select([sum('kills').as('kills'), sum('deaths').as('deaths'), sum('deaths_with_weapon').as('deaths_while_equipped'), 'attacker_id', sql`last(attacker_name)`.as('username'), sum('total_distance').as('total_distance'), max('max_distance').as('max_distance')]).groupBy('attacker_id') + const test = (await selection.execute()).reduce>((acc, curr) => { + acc[curr.attacker_id] = { + kills: Number(curr.kills), + deaths: Number(curr.deaths), + max_distance: Number(curr.max_distance), + total_distance: Number(curr.total_distance), + deaths_while_equipped: Number(curr.deaths_while_equipped), + username: curr.username + } + return acc + }, {}) + res.send(test) + })() + }) + +router.get('/:dataType', param('dataType') - .custom( - (e) => - e == 'weapons' || - e == 'players' || - e == 'maps' || - e == 'servers' || - e == 'gamemodes' - ) - .withMessage('Only weapons, players, maps or servers are valid paths'), - query(['server', 'map', 'weapon', 'gamemode', 'player', 'host']) - .optional() - .isString(), + .custom((e) => e in path) + .withMessage('Only weapons, players, maps, gamemodes or servers are valid paths'), validateErrors, (req, res) => { - const data: { - [key: string]: { - deaths: number - kills: number - max_distance: number - total_distance: number - username?: string - host?: number - deaths_while_equipped?: number + void (async () => { + let data = db.selectFrom('kill_view') + if (req.query) { + data = processQueryArgs(data, req.query as unknown as string | string[]) } - } = {} - let index: - | 'cause_of_death' - | 'attacker_id' - | 'map' - | 'servername' - | 'game_mode' - switch (req.params.dataType) { - case 'weapons': - index = 'cause_of_death' - break - case 'players': - index = 'attacker_id' - break - case 'maps': - index = 'map' - break - case 'servers': - index = 'servername' - break - case 'gamemodes': - index = 'game_mode' - break - default: - return res.status(400).send() - } - const timeStart = new Date() - allData - .filter((e) => filters(e, req.query)) - .forEach((e) => { - if ( - !e.cause_of_death || - !e.attacker_id || - !e.map || - !e.servername || - !e.game_mode - ) - return - const requestIndex = e[index] - if (!requestIndex) return - if (!data[requestIndex]) - data[requestIndex] = { - deaths: 0, - kills: 0, - max_distance: 0, - total_distance: 0 - } - if (index === 'attacker_id') - data[requestIndex].username = e.attacker_name - if (index === 'servername') data[requestIndex].host = e.host - if ( - index === 'cause_of_death' || - (req.query.weapon && - !req.query.weapon.toString().startsWith('!') && - index === 'attacker_id') - ) - data[requestIndex].deaths_while_equipped = - Number(e.deaths_with_weapon) + - (data[requestIndex].deaths_while_equipped || 0) - data[requestIndex].deaths += Number(e.deaths) - data[requestIndex].kills += Number(e.kills) - data[requestIndex].total_distance += Number(e.total_distance) - data[requestIndex].max_distance = Math.max( - data[requestIndex].max_distance, - Number(e.max_distance) - ) - }) - console.log( - new Date().toLocaleString() + ',' + - (req.headers['x-forwarded-for']?.toString() || - req.socket.remoteAddress?.toString() || - '') + - ',' + - Math.abs(new Date().getTime() - timeStart.getTime()) / 1000 + ',' + req.originalUrl - ) - const dataString = JSON.stringify(data) - const buffer = Buffer.from(dataString) - const size = buffer.length - res.status(200).setHeader('X-File-Size', size).setHeader('Content-Type', 'application/json').send(buffer) - } -) + const dataType = req.params.dataType as keyof typeof path + + const selection = data.select([sum('kills').as('kills'), sum('deaths').as('deaths'), sum('deaths_with_weapon').as('deaths_while_equipped'), path[dataType], sum('total_distance').as('total_distance'), max('max_distance').as('max_distance')]).groupBy(path[dataType]) + const test = (await selection.execute()).reduce>((acc, curr) => { + acc[curr[path[dataType]]] = { + kills: Number(curr.kills), + deaths: Number(curr.deaths), + max_distance: Number(curr.max_distance), + total_distance: Number(curr.total_distance), + deaths_while_equipped: Number(curr.deaths_while_equipped) + } + return acc + }, {}) + res.send(test) + })() + }) export default router diff --git a/src/clientMain.ts b/src/clientMain.ts index 8c1ef86..9fe8d28 100644 --- a/src/clientMain.ts +++ b/src/clientMain.ts @@ -1,36 +1,33 @@ import * as dotenv from 'dotenv' import cluster from 'cluster' import os from 'os' -dotenv.config() import express from 'express' import cors from 'cors' import client from './client/client' import { dbReady } from './db/db' -import processAll from './process/process' -import listenKills from './process/onKill' +dotenv.config() -const cCPUs = os.cpus().length; +const cCPUs = os.cpus().length const port = 3000 -if (cluster.isPrimary) { +if (cluster.isPrimary && process.env.ENVIRONMENT !== 'dev') { // Create a worker for each CPU for (let i = 0; i < cCPUs; i++) { - cluster.fork(); + cluster.fork() } cluster.on('online', function (worker) { - console.log('Worker ' + worker.process.pid + ' is online.'); - }); + console.log(`Worker ${worker.process.pid ?? ''} is online`) + }) cluster.on('exit', function (worker, code, signal) { - console.log('worker ' + worker.process.pid + ' died.'); - }); + console.log(`Worker ${worker.process.pid ?? ''} died`) + }) } - - export default - new Promise(async (resolve, reject) => { - if (!cluster.isPrimary) { +new Promise((resolve, reject) => { + void (async () => { + if (!cluster.isPrimary || process.env.ENVIRONMENT === 'dev') { const app = express() app.use(express.json()) app.use(cors({ exposedHeaders: ['X-File-Size', 'Content-Encoding'] })) @@ -41,11 +38,10 @@ export default app.use('/', client) await dbReady() - await processAll() - await listenKills() const listenServer = app.listen(port, '0.0.0.0', () => { console.log(`Tone client api listening on port ${port}`) resolve(listenServer) }) } - }) \ No newline at end of file + })() +}) diff --git a/src/common.ts b/src/common.ts index 040da85..b89efbe 100644 --- a/src/common.ts +++ b/src/common.ts @@ -1,11 +1,11 @@ -import { RequestHandler } from 'express' -import { Result, validationResult } from 'express-validator' +import { type RequestHandler } from 'express' +import { validationResult } from 'express-validator' import http from 'http' import https from 'https' -export function GetRequest(url: string) { - return new Promise((resolve, reject) => { - let handler = (resp: http.IncomingMessage) => { +export async function GetRequest (url: string) { + return await new Promise((resolve, reject) => { + const handler = (resp: http.IncomingMessage) => { let data = '' // A chunk of data has been received. diff --git a/src/db/db.ts b/src/db/db.ts index 00c72e7..4442cb8 100644 --- a/src/db/db.ts +++ b/src/db/db.ts @@ -1,9 +1,10 @@ import * as dotenv from 'dotenv' -dotenv.config() -import { InsertObject, Kysely, PostgresDialect } from 'kysely' +import { Kysely, PostgresDialect } from 'kysely' import { Pool } from 'pg' import migrateToLatest from './migrations' -import Database, { KillTable } from './model' +import { type KillTable } from './model' +import type Database from './model' +dotenv.config() const migration = migrateToLatest() const db = new Kysely({ dialect: new PostgresDialect({ @@ -15,8 +16,8 @@ const db = new Kysely({ max: 30 }) }), - log(event) { - if (process.env.ENVIRONMENT != 'production') { + log (event) { + if (process.env.ENVIRONMENT !== 'dev') { return } if (event.level === 'query') { @@ -33,19 +34,19 @@ interface RemoveFromKill { type KillRecord = Omit -export async function CreateKillRecord(data: KillRecord) { +export async function CreateKillRecord (data: KillRecord) { await db .insertInto('kill') .values({ ...data }) .execute() } -export async function getHostList() { - return await db.selectFrom("host").select(['id', 'host.name']).execute() +export async function getHostList () { + return await db.selectFrom('host').select(['id', 'host.name']).execute() } -//tokens are stored in raw... maybe we should use something better in the future -//Using callback for express-basic-auth -export function CheckServerToken(token: string) { - return db.selectFrom('host').select('id') +// tokens are stored in raw... maybe we should use something better in the future +// Using callback for express-basic-auth +export async function CheckServerToken (token: string) { + return await db.selectFrom('host').select('id') .where('token', '=', Buffer.from(token, 'base64').toString()) .executeTakeFirst() .then((result) => { @@ -53,7 +54,7 @@ export function CheckServerToken(token: string) { }) } -export async function dbReady(): Promise> { +export async function dbReady (): Promise> { await migration return db } diff --git a/src/db/migrations/2023-05-29-01 kill_view.ts b/src/db/migrations/2023-05-29-01 kill_view.ts new file mode 100644 index 0000000..a2090fa --- /dev/null +++ b/src/db/migrations/2023-05-29-01 kill_view.ts @@ -0,0 +1,126 @@ +import { type Kysely } from 'kysely' +import { Client } from 'pg' + +const pgClient = new Client({ + host: process.env.POSTGRES_HOST, + database: process.env.POSTGRES_DATABASE, + user: process.env.POSTGRES_USER, + password: process.env.POSTGRES_PASSWORD +}) + +export async function up (db: Kysely): Promise { + await pgClient.connect() + await pgClient.query('DROP TABLE IF EXISTS kill_view;') + console.log('creating table kill_view') + await pgClient.query(`CREATE TABLE kill_view + AS ( + with "kills" as (select count("id") as "kills", coalesce(max("distance"), 0) as "max_distance", coalesce(sum("distance"), 0) as "total_distance", "attacker_id", last(attacker_name) as "attacker_name", "cause_of_death", "map", "game_mode", "servername", "host" from "kill" where "attacker_id" != "victim_id" group by "attacker_id", "cause_of_death", "map", "servername", "host", "game_mode"), "deaths" as (select count("id") as "deaths", "victim_id", last(victim_name) as "victim_name", "cause_of_death", "map", "game_mode", "servername", "host" from "kill" group by "victim_id", "cause_of_death", "map", "servername", "host", "game_mode"), "deathswithweapon" as (select count("id") as "deaths", "victim_id", "victim_current_weapon", "map", "game_mode", "servername", "host" from "kill" group by "victim_id", "victim_current_weapon", "map", "servername", "host", "game_mode") select COALESCE(kills.attacker_name, deaths.victim_name) as "attacker_name", COALESCE(kills.attacker_id, deaths.victim_id) as "attacker_id", COALESCE(kills.kills, 0) as "kills", COALESCE(kills.total_distance, 0) as "total_distance", COALESCE(deathswithweapon.deaths, 0) as "deaths_with_weapon", COALESCE(kills.max_distance, 0) as "max_distance", COALESCE(deaths.deaths, 0) as "deaths", COALESCE(kills.servername, deaths.servername) as "servername", COALESCE(kills.host, deaths.host) as "host", COALESCE(kills.cause_of_death, deaths.cause_of_death) as "cause_of_death", COALESCE(kills.map, deaths.map) as "map", COALESCE(kills.game_mode, deaths.game_mode) as "game_mode" from "kills" full join "deaths" on "deaths"."victim_id" = "kills"."attacker_id" and "deaths"."cause_of_death" = "kills"."cause_of_death" and "deaths"."servername" = "kills"."servername" and "deaths"."host" = "kills"."host" and "deaths"."game_mode" = "kills"."game_mode" and "deaths"."map" = "kills"."map" left join "deathswithweapon" on "deathswithweapon"."victim_id" = "kills"."attacker_id" and "deathswithweapon"."victim_current_weapon" = "kills"."cause_of_death" and "deathswithweapon"."servername" = "kills"."servername" and "deathswithweapon"."host" = "kills"."host" and "deathswithweapon"."game_mode" = "kills"."game_mode" and "deathswithweapon"."map" = "kills"."map" + );`) + console.log('creating index on attacker_id') + await pgClient.query('CREATE INDEX ON kill_view USING HASH ("attacker_id");') + console.log('creating index on map') + await pgClient.query('CREATE INDEX ON kill_view USING HASH ("map");') + console.log('creating index on game_mode') + await pgClient.query('CREATE INDEX ON kill_view USING HASH ("game_mode");') + console.log('creating index on cause_of_death') + await pgClient.query('CREATE INDEX ON kill_view USING HASH ("cause_of_death");') + console.log('creating index on server') + await pgClient.query('CREATE INDEX ON kill_view ("servername", "host");') + console.log('creating function update_kill_view_fnct') + await pgClient.query(`CREATE OR REPLACE FUNCTION update_kill_view_fnct() + RETURNS TRIGGER +AS $$ +BEGIN + IF EXISTS( + SELECT * FROM kill_view + WHERE + new.attacker_id = attacker_id AND + new.map = map AND + new.game_mode = game_mode AND + new.cause_of_death = cause_of_death AND + new.servername = servername AND + new.host = host + ) THEN + UPDATE kill_view SET kills = kills + 1, + max_distance = (SELECT Max(v) FROM (VALUES (new.distance), (max_distance)) AS value(v)), + total_distance = total_distance + new.distance, + attacker_name = new.attacker_name + WHERE + new.attacker_id = attacker_id AND + new.map = map AND + new.game_mode = game_mode AND + new.cause_of_death = cause_of_death AND + new.servername = servername AND + new.host = host; + ELSE + INSERT INTO kill_view(kills,deaths, deaths_with_weapon, attacker_id, map, game_mode, cause_of_death, servername, host, max_distance, total_distance) + VALUES(1,0,0, new.attacker_id, new.map, new.game_mode, new.cause_of_death, new.servername, new.host,new.distance, new.distance); + END IF; + + + IF EXISTS( + SELECT * FROM kill_view + WHERE + new.victim_id = attacker_id AND + new.map = map AND + new.game_mode = game_mode AND + new.cause_of_death = cause_of_death AND + new.servername = servername AND + new.host = host + ) THEN + UPDATE kill_view SET deaths = deaths + 1 + WHERE + new.victim_id = attacker_id AND + new.map = map AND + new.game_mode = game_mode AND + new.cause_of_death = cause_of_death AND + new.servername = servername AND + new.host = host; + ELSE + INSERT INTO kill_view(deaths, kills, deaths_with_weapon, attacker_id, map, game_mode, cause_of_death, servername, host, max_distance, total_distance) + VALUES(1,0,0, new.victim_id, new.map, new.game_mode, new.cause_of_death, new.servername, new.host,0,0); + END IF; + + + IF EXISTS( + SELECT * FROM kill_view + WHERE + new.victim_id = attacker_id AND + new.map = map AND + new.game_mode = game_mode AND + new.attacker_current_weapon = cause_of_death AND + new.servername = servername AND + new.host = host + ) THEN + UPDATE kill_view SET deaths_with_weapon = deaths_with_weapon + 1 + WHERE + new.victim_id = attacker_id AND + new.map = map AND + new.game_mode = game_mode AND + new.attacker_current_weapon = cause_of_death AND + new.servername = servername AND + new.host = host; + ELSE + INSERT INTO kill_view(deaths, kills, deaths_with_weapon, attacker_id, map, game_mode, cause_of_death, servername, host, max_distance, total_distance) + VALUES(0,0,1, new.victim_id, new.map, new.game_mode, new.attacker_current_weapon, new.servername, new.host,0,0); + END IF; + + + RETURN NEW; +END; +$$ LANGUAGE PLPGSQL;`) + console.log('creating trigger update_kill_view') + await pgClient.query(`CREATE OR REPLACE TRIGGER update_kill_view +AFTER INSERT ON kill +FOR EACH ROW +EXECUTE FUNCTION update_kill_view_fnct();`) + await pgClient.end() +} + +export async function down (db: Kysely): Promise { + await pgClient.connect() + await pgClient.query('DROP TRIGGER IF EXISTS update_kill_view;') + await pgClient.query('DROP FUNCTION IF EXISTS update_kill_view_fnct') + await pgClient.query('DROP TABLE IF EXISTS kill_view;') + await pgClient.end() +} diff --git a/src/db/model.ts b/src/db/model.ts index 614b956..f54cfd4 100644 --- a/src/db/model.ts +++ b/src/db/model.ts @@ -1,4 +1,4 @@ -import { ColumnType, Generated } from 'kysely' +import { type Generated } from 'kysely' export interface KillTable { id: Generated @@ -43,37 +43,30 @@ export interface KillTable { distance: number titan?: string } -/* -interface PlayerTable { - id: number - name: string - 'opt-out': boolean - hide_TOS: boolean -} -*/ -interface WeaponTable { - id: string - name: string - description: string - image: string -} -interface MapTable { - id: string - name: string - description: string - image: string +export interface KillViewTable { + kills: number + deaths: number + deaths_with_weapon: number + attacker_id: number + attacker_name: string + map: string + game_mode: string + cause_of_death: string + servername: string + host: number + max_distance: number + total_distance: number } + interface HosterTable { id: Generated name: string token: Generated } interface Database { + kill_view: KillViewTable kill: KillTable - //player: PlayerTable - weapon: WeaponTable - maps: MapTable host: HosterTable } diff --git a/src/process/onKill.ts b/src/process/onKill.ts index c923fc1..825f711 100644 --- a/src/process/onKill.ts +++ b/src/process/onKill.ts @@ -1,111 +1,113 @@ import { Client } from 'pg' -import { allData } from './process' +// import { allData } from './process' export const pgClient = new Client({ - host: process.env.POSTGRES_HOST, - database: process.env.POSTGRES_DATABASE, - user: process.env.POSTGRES_USER, - password: process.env.POSTGRES_PASSWORD + host: process.env.POSTGRES_HOST, + database: process.env.POSTGRES_DATABASE, + user: process.env.POSTGRES_USER, + password: process.env.POSTGRES_PASSWORD }) -export default async function listenKills() { - await pgClient.connect() - await pgClient.query('LISTEN new_kill') +export default async function listenKills () { + await pgClient.connect() + await pgClient.query('LISTEN new_kill') - pgClient.on('notification', (data) => { - if (!data.payload) return - const payload = JSON.parse(data.payload) - let killEntry = allData.find( - (e) => - e.attacker_id == payload.attacker_id && + /* pgClient.on('notification', (data) => { + if (!data.payload) return + const payload = JSON.parse(data.payload) + + let killEntry = allData.find( + (e) => + e.attacker_id == payload.attacker_id && e.cause_of_death == payload.cause_of_death && e.game_mode == payload.game_mode && e.host == payload.host && e.map == payload.map && e.servername == payload.servername - ) - let deathEntry = allData.find( - (e) => - e.attacker_id == payload.victim_id && + ) + let deathEntry = allData.find( + (e) => + e.attacker_id == payload.victim_id && e.cause_of_death == payload.cause_of_death && e.game_mode == payload.game_mode && e.host == payload.host && e.map == payload.map && e.servername == payload.servername - ) - let deathWithWeaponEntry = allData.find( - (e) => - e.attacker_id == payload.victim_id && + ) + let deathWithWeaponEntry = allData.find( + (e) => + e.attacker_id == payload.victim_id && e.cause_of_death == payload.victim_current_weapon && e.game_mode == payload.game_mode && e.host == payload.host && e.map == payload.map && e.servername == payload.servername - ) - if (!killEntry) { - killEntry = { - kills: 0, - deaths: 0, - max_distance: 0, - total_distance: 0, - deaths_with_weapon: 0, - attacker_name: payload.attacker_name, - attacker_id: payload.attacker_id, - cause_of_death: payload.cause_of_death, - game_mode: payload.game_mode, - host: payload.host, - map: payload.map, - servername: payload.servername - } - allData.push(killEntry) - } + ) + if (!killEntry) { + killEntry = { + kills: 0, + deaths: 0, + max_distance: 0, + total_distance: 0, + deaths_with_weapon: 0, + attacker_name: payload.attacker_name, + attacker_id: payload.attacker_id, + cause_of_death: payload.cause_of_death, + game_mode: payload.game_mode, + host: payload.host, + map: payload.map, + servername: payload.servername + } + allData.push(killEntry) + } - if (!deathEntry) { - deathEntry = { - kills: 0, - deaths: 0, - max_distance: 0, - total_distance: 0, - deaths_with_weapon: 0, - attacker_name: payload.victim_name, - attacker_id: payload.victim_id, - cause_of_death: payload.cause_of_death, - game_mode: payload.game_mode, - host: payload.host, - map: payload.map, - servername: payload.servername - } - allData.push(deathEntry) - } + if (!deathEntry) { + deathEntry = { + kills: 0, + deaths: 0, + max_distance: 0, + total_distance: 0, + deaths_with_weapon: 0, + attacker_name: payload.victim_name, + attacker_id: payload.victim_id, + cause_of_death: payload.cause_of_death, + game_mode: payload.game_mode, + host: payload.host, + map: payload.map, + servername: payload.servername + } + allData.push(deathEntry) + } - if (!deathWithWeaponEntry) { - deathWithWeaponEntry = { - kills: 0, - deaths: 0, - max_distance: 0, - total_distance: 0, - deaths_with_weapon: 0, - attacker_name: payload.victim_name, - attacker_id: payload.victim_id, - cause_of_death: payload.victim_current_weapon, - game_mode: payload.game_mode, - host: payload.host, - map: payload.map, - servername: payload.servername - } - allData.push(deathWithWeaponEntry) - } + if (!deathWithWeaponEntry) { + deathWithWeaponEntry = { + kills: 0, + deaths: 0, + max_distance: 0, + total_distance: 0, + deaths_with_weapon: 0, + attacker_name: payload.victim_name, + attacker_id: payload.victim_id, + cause_of_death: payload.victim_current_weapon, + game_mode: payload.game_mode, + host: payload.host, + map: payload.map, + servername: payload.servername + } + allData.push(deathWithWeaponEntry) + } - if (payload.victim_id != payload.attacker_id) { - killEntry.kills++ - killEntry.total_distance = Number(killEntry.total_distance) + Number(payload.distance) - killEntry.max_distance = Math.max(killEntry.max_distance || 0, payload.distance) - } - deathEntry.deaths++ - deathEntry.attacker_name = payload.victim_name - deathWithWeaponEntry.deaths_with_weapon++ - deathWithWeaponEntry.attacker_name = payload.victim_name - killEntry.attacker_name = payload.attacker_name - }) - return pgClient + if (payload.victim_id != payload.attacker_id) { + killEntry.kills++ + killEntry.total_distance = Number(killEntry.total_distance) + Number(payload.distance) + killEntry.max_distance = Math.max(killEntry.max_distance || 0, payload.distance) + } + deathEntry.deaths++ + deathEntry.attacker_name = payload.victim_name + deathWithWeaponEntry.deaths_with_weapon++ + deathWithWeaponEntry.attacker_name = payload.victim_name + killEntry.attacker_name = payload.attacker_name + + }) */ + return pgClient } diff --git a/src/process/process.ts b/src/process/process.ts index 829be7d..5513ca0 100644 --- a/src/process/process.ts +++ b/src/process/process.ts @@ -1,6 +1,6 @@ import db from '../db/db' -const { count, max, sum, coalesce } = db.fn import { sql } from 'kysely' +const { count, max, sum, coalesce } = db.fn export let allData: Awaited> @@ -8,23 +8,16 @@ export let allData: Awaited> * populates allData * @returns */ -async function processAll() { +async function processAll (): Promise { console.log('Starting data calculation...') const timeStart = new Date() - allData = await processGlobalStats() + // allData = await processGlobalStats() - console.log( - 'Data calculation finished. Took + ' + - Math.abs(new Date().getTime() - timeStart.getTime()) / 1000 + - ' seconds' - ) - if (process.env.ENVIRONMENT == 'production') { - return - } + console.log(`Data calculation finished. Took + ${Math.abs(new Date().getTime() - timeStart.getTime()) / 1000} seconds`) } -async function processGlobalStats() { +async function processGlobalStats () { return await db .with('kills', (db) => db @@ -117,7 +110,7 @@ async function processGlobalStats() { .onRef('deathswithweapon.game_mode', '=', 'kills.game_mode') .onRef('deathswithweapon.map', '=', 'kills.map') ) - //.selectAll('kills') + // .selectAll('kills') .select([ sql`COALESCE(kills.attacker_name, deaths.victim_name)`.as('attacker_name'), sql`COALESCE(kills.attacker_id, deaths.victim_id)`.as('attacker_id'), @@ -130,7 +123,7 @@ async function processGlobalStats() { sql`COALESCE(kills.host, deaths.host)`.as('host'), sql`COALESCE(kills.cause_of_death, deaths.cause_of_death)`.as('cause_of_death'), sql`COALESCE(kills.map, deaths.map)`.as('map'), - sql`COALESCE(kills.game_mode, deaths.game_mode)`.as('game_mode'), + sql`COALESCE(kills.game_mode, deaths.game_mode)`.as('game_mode') ]) .execute() }