Non-working breaking changes
This commit is contained in:
+24
-31
@@ -41,43 +41,36 @@ export async function CreateKillRecord(data: KillRecord) {
|
|||||||
.execute()
|
.execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function FindServer({ name }: { name: string }) {
|
// export async function FindServer({ name }: { name: string }) {
|
||||||
return await db
|
// return await db
|
||||||
.selectFrom('server')
|
// .selectFrom('server')
|
||||||
.select(['server.name', 'server.description'])
|
// .select(['server.name', 'server.description'])
|
||||||
.where('server.name', '=', name)
|
// .where('server.name', '=', name)
|
||||||
.executeTakeFirst()
|
// .executeTakeFirst()
|
||||||
}
|
// }
|
||||||
|
|
||||||
export async function CreateServer({
|
// export async function CreateServer({
|
||||||
name,
|
// name,
|
||||||
description
|
// description
|
||||||
}: {
|
// }: {
|
||||||
name: string
|
// name: string
|
||||||
description: string
|
// description: string
|
||||||
}) {
|
// }) {
|
||||||
return await db
|
// return await db
|
||||||
.insertInto('server')
|
// .insertInto('server')
|
||||||
.values({ name, description })
|
// .values({ name, description })
|
||||||
.returning(['id', 'token'])
|
// .returning(['id', 'token'])
|
||||||
.executeTakeFirstOrThrow()
|
// .executeTakeFirstOrThrow()
|
||||||
}
|
// }
|
||||||
|
|
||||||
//tokens are stored in raw... maybe we should use something better in the future
|
//tokens are stored in raw... maybe we should use something better in the future
|
||||||
//Using callback for express-basic-auth
|
//Using callback for express-basic-auth
|
||||||
export function CheckServerToken(
|
export function CheckServerToken(token: string) {
|
||||||
this: { params: any, body: any },
|
return db.selectFrom('hoster').select('id')
|
||||||
name: string,
|
.where('token', '=', Buffer.from(token, 'base64').toString())
|
||||||
password: string,
|
|
||||||
cb: (error: Error | null, success: boolean) => void
|
|
||||||
) {
|
|
||||||
db.selectFrom('server')
|
|
||||||
.where('id', '=', Number(name))
|
|
||||||
.where('token', '=', password)
|
|
||||||
.executeTakeFirst()
|
.executeTakeFirst()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (name != this.params.serverId) return cb(null, false)
|
return result
|
||||||
return cb(null, !!result)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -17,9 +17,12 @@ export async function up(db: Kysely<any>): Promise<void> {
|
|||||||
|
|
||||||
await pgClient.query('ALTER TABLE server RENAME TO hoster')
|
await pgClient.query('ALTER TABLE server RENAME TO hoster')
|
||||||
await pgClient.query('ALTER TABLE hoster DROP COLUMN description')
|
await pgClient.query('ALTER TABLE hoster DROP COLUMN description')
|
||||||
|
await pgClient.query('ALTER TABLE kill ADD COLUMN host integer NULL')
|
||||||
|
//Update the hosts column once the hoster table is manually updated
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function down(db: Kysely<any>): Promise<void> {
|
export async function down(db: Kysely<any>): Promise<void> {
|
||||||
|
await pgClient.query('ALTER TABLE kill DROP COLUMN host')
|
||||||
await pgClient.query('ALTER TABLE hoster add description character varying NULL')
|
await pgClient.query('ALTER TABLE hoster add description character varying NULL')
|
||||||
await pgClient.query('ALTER TABLE hoster RENAME TO server')
|
await pgClient.query('ALTER TABLE hoster RENAME TO server')
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -2,7 +2,8 @@ import { ColumnType, Generated } from 'kysely'
|
|||||||
|
|
||||||
export interface KillTable {
|
export interface KillTable {
|
||||||
id: Generated<number>
|
id: Generated<number>
|
||||||
server: number
|
servername: string
|
||||||
|
host: number
|
||||||
killstat_version: string
|
killstat_version: string
|
||||||
match_id: string
|
match_id: string
|
||||||
game_mode: string
|
game_mode: string
|
||||||
@@ -56,10 +57,9 @@ interface MapTable {
|
|||||||
description: string
|
description: string
|
||||||
image: string
|
image: string
|
||||||
}
|
}
|
||||||
interface ServerTable {
|
interface HosterTable {
|
||||||
id: Generated<number>
|
id: Generated<number>
|
||||||
name: string
|
name: string
|
||||||
description: string
|
|
||||||
token: Generated<string>
|
token: Generated<string>
|
||||||
}
|
}
|
||||||
interface Database {
|
interface Database {
|
||||||
@@ -67,7 +67,7 @@ interface Database {
|
|||||||
player: PlayerTable
|
player: PlayerTable
|
||||||
weapon: WeaponTable
|
weapon: WeaponTable
|
||||||
maps: MapTable
|
maps: MapTable
|
||||||
server: ServerTable
|
hoster: HosterTable
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Database
|
export default Database
|
||||||
|
|||||||
+18
-16
@@ -22,44 +22,46 @@ export default async function listenKills() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function updateGlobal({ cause_of_death, distance, attacker_id, victim_id, server }: { cause_of_death: string, distance: number, attacker_id: string, victim_id: string, server: number }) {
|
async function updateGlobal({ cause_of_death, distance, attacker_id, victim_id, servername, host }: { cause_of_death: string, distance: number, attacker_id: string, victim_id: string, servername: string, host: number }) {
|
||||||
|
servername = servername.replace(/[^a-z0-9]/gi, '')
|
||||||
const promises: Promise<any>[] = []
|
const promises: Promise<any>[] = []
|
||||||
|
|
||||||
if (!await client.json.type('kills')) await client.json.set('kills', '', { data: {}, weapons: {}, servers: {}, players: {} })
|
if (!await client.json.type('kills')) await client.json.set('kills', '', { data: {}, weapons: {}, servers: {}, players: {} })
|
||||||
|
|
||||||
if (!await client.json.type('kills', genPrefix.weapon({ cause_of_death }))) await client.json.set('kills', genPrefix.weapon({ cause_of_death }), { players: {}, max_distance: 0, kills: 0, total_distance: 0 })
|
if (!await client.json.type('kills', genPrefix.weapon({ cause_of_death }))) await client.json.set('kills', genPrefix.weapon({ cause_of_death }), { players: {}, max_distance: 0, kills: 0, total_distance: 0 })
|
||||||
if (!await client.json.type('kills', genPrefix.player({ attacker_id }))) await client.json.set('kills', genPrefix.player({ attacker_id }), { weapons: {}, max_distance: 0, kills: 0, deaths: 0, total_distance: 0 })
|
if (!await client.json.type('kills', genPrefix.player({ attacker_id }))) await client.json.set('kills', genPrefix.player({ attacker_id }), { weapons: {}, max_distance: 0, kills: 0, deaths: 0, total_distance: 0 })
|
||||||
if (!await client.json.type('kills', `servers.${server}`)) await client.json.set('kills', `servers.${server}`, { data: {}, weapons: {}, players: {}, max_distance: 0, kills: 0, total_distance: 0 })
|
if (!await client.json.type('kills', `servers.${host}`)) await client.json.set('kills', `servers.${host}`, {})
|
||||||
if (!await client.json.type('kills', genPrefix.weapon({ cause_of_death, server }))) await client.json.set('kills', genPrefix.weapon({ cause_of_death, server }), { players: {}, max_distance: 0, kills: 0, total_distance: 0 })
|
if (!await client.json.type('kills', `servers.${host}.${servername}`)) await client.json.set('kills', `servers.${host}.${servername}`, { data: {}, weapons: {}, players: {}, max_distance: 0, kills: 0, total_distance: 0 })
|
||||||
if (!await client.json.type('kills', genPrefix.player({ attacker_id, server }))) await client.json.set('kills', genPrefix.player({ attacker_id, server }), { weapons: {}, max_distance: 0, kills: 0, deaths: 0, total_distance: 0 })
|
if (!await client.json.type('kills', genPrefix.weapon({ cause_of_death, server: `${host}.${servername}` }))) await client.json.set('kills', genPrefix.weapon({ cause_of_death, server: `${host}.${servername}` }), { players: {}, max_distance: 0, kills: 0, total_distance: 0 })
|
||||||
|
if (!await client.json.type('kills', genPrefix.player({ attacker_id, server: `${host}.${servername}` }))) await client.json.set('kills', genPrefix.player({ attacker_id, server: `${host}.${servername}` }), { weapons: {}, max_distance: 0, kills: 0, deaths: 0, total_distance: 0 })
|
||||||
|
|
||||||
if (!await client.json.type('kills', genPrefix.player({ attacker_id: victim_id, server }))) await client.json.set('kills', genPrefix.player({ attacker_id: victim_id, server }), { weapons: {}, max_distance: 0, kills: 0, deaths: 0, total_distance: 0 })
|
if (!await client.json.type('kills', genPrefix.player({ attacker_id: victim_id, server: `${host}.${servername}` }))) await client.json.set('kills', genPrefix.player({ attacker_id: victim_id, server: `${host}.${servername}` }), { weapons: {}, max_distance: 0, kills: 0, deaths: 0, total_distance: 0 })
|
||||||
if (!await client.json.type('kills', genPrefix.player({ attacker_id: victim_id }))) await client.json.set('kills', genPrefix.player({ attacker_id: victim_id }), { weapons: {}, max_distance: 0, kills: 0, deaths: 0, total_distance: 0 })
|
if (!await client.json.type('kills', genPrefix.player({ attacker_id: victim_id }))) await client.json.set('kills', genPrefix.player({ attacker_id: victim_id }), { weapons: {}, max_distance: 0, kills: 0, deaths: 0, total_distance: 0 })
|
||||||
|
|
||||||
if (!await client.json.type('kills', genPrefix.weaponPlayers({ attacker_id: victim_id, cause_of_death }))) await client.json.set('kills', genPrefix.weaponPlayers({ attacker_id: victim_id, cause_of_death }), { max_distance: 0, kills: 0, deaths: 0, total_distance: 0 })
|
if (!await client.json.type('kills', genPrefix.weaponPlayers({ attacker_id: victim_id, cause_of_death }))) await client.json.set('kills', genPrefix.weaponPlayers({ attacker_id: victim_id, cause_of_death }), { max_distance: 0, kills: 0, deaths: 0, total_distance: 0 })
|
||||||
if (!await client.json.type('kills', genPrefix.playerWeapons({ attacker_id: victim_id, cause_of_death }))) await client.json.set('kills', genPrefix.playerWeapons({ attacker_id: victim_id, cause_of_death }), { max_distance: 0, kills: 0, total_distance: 0 })
|
if (!await client.json.type('kills', genPrefix.playerWeapons({ attacker_id: victim_id, cause_of_death }))) await client.json.set('kills', genPrefix.playerWeapons({ attacker_id: victim_id, cause_of_death }), { max_distance: 0, kills: 0, total_distance: 0 })
|
||||||
|
|
||||||
if (!await client.json.type('kills', genPrefix.weaponPlayers({ attacker_id: victim_id, cause_of_death, server }))) await client.json.set('kills', genPrefix.weaponPlayers({ attacker_id: victim_id, cause_of_death, server }), { max_distance: 0, kills: 0, deaths: 0, total_distance: 0 })
|
if (!await client.json.type('kills', genPrefix.weaponPlayers({ attacker_id: victim_id, cause_of_death, server: `${host}.${servername}` }))) await client.json.set('kills', genPrefix.weaponPlayers({ attacker_id: victim_id, cause_of_death, server: `${host}.${servername}` }), { max_distance: 0, kills: 0, deaths: 0, total_distance: 0 })
|
||||||
if (!await client.json.type('kills', genPrefix.playerWeapons({ attacker_id: victim_id, cause_of_death, server }))) await client.json.set('kills', genPrefix.playerWeapons({ attacker_id: victim_id, cause_of_death, server }), { max_distance: 0, kills: 0, total_distance: 0 })
|
if (!await client.json.type('kills', genPrefix.playerWeapons({ attacker_id: victim_id, cause_of_death, server: `${host}.${servername}` }))) await client.json.set('kills', genPrefix.playerWeapons({ attacker_id: victim_id, cause_of_death, server: `${host}.${servername}` }), { max_distance: 0, kills: 0, total_distance: 0 })
|
||||||
|
|
||||||
promises.push(updatePath(`data`, { distance }))
|
promises.push(updatePath(`data`, { distance }))
|
||||||
//servers.1
|
//servers.1
|
||||||
promises.push(updatePath(`servers.${server}`, { distance }).then(() => Promise.all([
|
promises.push(updatePath(`servers.${host}.${servername}`, { distance }).then(() => Promise.all([
|
||||||
//servers.1.players.123456789
|
//servers.1.players.123456789
|
||||||
updatePath(`servers.${server}.players.${attacker_id}`, { distance }).then(async () => {
|
updatePath(`servers.${host}.${servername}.players.${attacker_id}`, { distance }).then(async () => {
|
||||||
if (!await client.json.type('kills', `servers.${server}.players.${victim_id}.deaths`)) await client.json.set('kills', `servers.${server}.players.${victim_id}.deaths`, 0)
|
if (!await client.json.type('kills', `servers.${host}.${servername}.players.${victim_id}.deaths`)) await client.json.set('kills', `servers.${host}.${servername}.players.${victim_id}.deaths`, 0)
|
||||||
await client.json.numIncrBy('kills', `servers.${server}.players.${victim_id}.deaths`, 1)
|
await client.json.numIncrBy('kills', `servers.${host}.${servername}.players.${victim_id}.deaths`, 1)
|
||||||
//servers.1.players.123456789.weapons.epg
|
//servers.1.players.123456789.weapons.epg
|
||||||
await updatePath(`servers.${server}.players.${attacker_id}.weapons.${cause_of_death}`, { distance })
|
await updatePath(`servers.${host}.${servername}.players.${attacker_id}.weapons.${cause_of_death}`, { distance })
|
||||||
}
|
}
|
||||||
|
|
||||||
),
|
),
|
||||||
//servers.1.weapons.epg
|
//servers.1.weapons.epg
|
||||||
updatePath(`servers.${server}.weapons.${cause_of_death}`, { distance }).then(async () => {
|
updatePath(`servers.${host}.${servername}.weapons.${cause_of_death}`, { distance }).then(async () => {
|
||||||
//servers.1.weapons.epg.players.123456789
|
//servers.1.weapons.epg.players.123456789
|
||||||
await updatePath(`servers.${server}.weapons.${cause_of_death}.players.${attacker_id}`, { distance })
|
await updatePath(`servers.${host}.${servername}.weapons.${cause_of_death}.players.${attacker_id}`, { distance })
|
||||||
if (!await client.json.type('kills', `servers.${server}.players.${victim_id}.deaths`)) await client.json.set('kills', `servers.${server}.weapons.${cause_of_death}.players.${victim_id}`, 0)
|
if (!await client.json.type('kills', `servers.${host}.${servername}.players.${victim_id}.deaths`)) await client.json.set('kills', `servers.${host}.${servername}.weapons.${cause_of_death}.players.${victim_id}`, 0)
|
||||||
await client.json.numIncrBy('kills', `servers.${server}.weapons.${cause_of_death}.players.${victim_id}.deaths`, 1)
|
await client.json.numIncrBy('kills', `servers.${host}.${servername}.weapons.${cause_of_death}.players.${victim_id}.deaths`, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
)])
|
)])
|
||||||
|
|||||||
+33
-26
@@ -3,19 +3,19 @@ const { count, max, sum } = db.fn
|
|||||||
import client from '../cache/redis'
|
import client from '../cache/redis'
|
||||||
|
|
||||||
export const genPrefix = {
|
export const genPrefix = {
|
||||||
global: ({ server }: { server?: number }) => {
|
global: ({ server }: { server?: string }) => {
|
||||||
return (server ? `servers.${server}.` : '') + 'data'
|
return (server ? `servers.${server}.` : '') + 'data'
|
||||||
},
|
},
|
||||||
weapon: ({ cause_of_death, server }: { cause_of_death: string, server?: number }) => {
|
weapon: ({ cause_of_death, server }: { cause_of_death: string, server?: string }) => {
|
||||||
return (server ? `servers.${server}.` : '') + `weapons.${cause_of_death}`
|
return (server ? `servers.${server}.` : '') + `weapons.${cause_of_death}`
|
||||||
},
|
},
|
||||||
player: ({ attacker_id, server }: { attacker_id: string, server?: number }) => {
|
player: ({ attacker_id, server }: { attacker_id: string, server?: string }) => {
|
||||||
return (server ? `servers.${server}.` : '') + `players.${attacker_id}`
|
return (server ? `servers.${server}.` : '') + `players.${attacker_id}`
|
||||||
},
|
},
|
||||||
playerWeapons: ({ cause_of_death, attacker_id, server }: { attacker_id: string, cause_of_death: string, server?: number }) => {
|
playerWeapons: ({ cause_of_death, attacker_id, server }: { attacker_id: string, cause_of_death: string, server?: string }) => {
|
||||||
return (server ? `servers.${server}.` : '') + `players.${attacker_id}.weapons.${cause_of_death}`
|
return (server ? `servers.${server}.` : '') + `players.${attacker_id}.weapons.${cause_of_death}`
|
||||||
},
|
},
|
||||||
weaponPlayers: ({ cause_of_death, attacker_id, server }: { attacker_id: string, cause_of_death: string, server?: number }) => {
|
weaponPlayers: ({ cause_of_death, attacker_id, server }: { attacker_id: string, cause_of_death: string, server?: string }) => {
|
||||||
return (server ? `servers.${server}.` : '') + `weapons.${cause_of_death}.players.${attacker_id}`
|
return (server ? `servers.${server}.` : '') + `weapons.${cause_of_death}.players.${attacker_id}`
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -112,12 +112,14 @@ async function processServerStats() {
|
|||||||
let promises: Promise<any>[] = []
|
let promises: Promise<any>[] = []
|
||||||
//Server global kills
|
//Server global kills
|
||||||
await db.selectFrom('kill')
|
await db.selectFrom('kill')
|
||||||
.select([count('id').as('kills'), max('distance').as('max_distance'), sum('distance').as('total_distance'), 'server'])
|
.select([count('id').as('kills'), max('distance').as('max_distance'), sum('distance').as('total_distance'), 'servername', 'host'])
|
||||||
.groupBy(['server']).execute().then(async (data) => {
|
.groupBy(['servername', 'host']).execute().then(async (data) => {
|
||||||
let transaction = client.multi()
|
let transaction = client.multi()
|
||||||
const p = data.map(async ({ kills, max_distance, total_distance, server }) => {
|
const p = data.map(async ({ kills, max_distance, total_distance, servername, host }) => {
|
||||||
if (!await client.json.type('kills', `servers.${server}`)) await client.json.set('kills', `servers.${server}`, { data: {}, weapons: {}, players: {} })
|
servername = servername.replace(/[^a-z0-9]/gi, '')
|
||||||
await processData(genPrefix.global({ server }), { total_distance, max_distance, kills }, transaction)
|
if (!await client.json.type('kills', `servers.${host}`)) await client.json.set('kills', `servers.${host}`, {})
|
||||||
|
if (!await client.json.type('kills', `servers.${host}.${servername}`)) await client.json.set('kills', `servers.${host}.${servername}`, { data: {}, weapons: {}, players: {} })
|
||||||
|
await processData(genPrefix.global({ server: `${host}.${servername}` }), { total_distance, max_distance, kills }, transaction)
|
||||||
})
|
})
|
||||||
await Promise.all(p)
|
await Promise.all(p)
|
||||||
return transaction.exec()
|
return transaction.exec()
|
||||||
@@ -125,53 +127,58 @@ async function processServerStats() {
|
|||||||
|
|
||||||
//Server weapon kills
|
//Server weapon kills
|
||||||
await db.selectFrom('kill')
|
await 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(async (data) => {
|
.select([count('id').as('kills'), max('distance').as('max_distance'), sum('distance').as('total_distance'), 'cause_of_death', 'servername', 'host']).groupBy(['cause_of_death', 'servername', 'host']).execute().then(async (data) => {
|
||||||
let transaction = client.multi()
|
let transaction = client.multi()
|
||||||
await Promise.all(data.map(async ({ kills, max_distance, total_distance, cause_of_death, server }) => {
|
await Promise.all(data.map(async ({ kills, max_distance, total_distance, cause_of_death, servername, host }) => {
|
||||||
const prefix = genPrefix.weapon({ cause_of_death, server })
|
servername = servername.replace(/[^a-z0-9]/gi, '')
|
||||||
|
const prefix = genPrefix.weapon({ cause_of_death, server: `${host}.${servername}` })
|
||||||
if (!await client.json.type('kills', prefix)) await client.json.set('kills', prefix, { players: {} })
|
if (!await client.json.type('kills', prefix)) await client.json.set('kills', prefix, { players: {} })
|
||||||
await processData(prefix, { kills, max_distance, total_distance }, transaction)
|
await processData(prefix, { kills, max_distance, total_distance }, transaction)
|
||||||
}))
|
}))
|
||||||
return transaction.exec()
|
return transaction.exec()
|
||||||
})
|
})
|
||||||
//server player kill
|
//server player kill
|
||||||
await 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']).whereRef("attacker_id", '!=', 'victim_id').execute()
|
await db.selectFrom('kill').select([count('id').as('kills'), max('distance').as('max_distance'), sum('distance').as('total_distance'), 'attacker_id', 'servername', 'host']).groupBy(['attacker_id', 'servername', 'host']).whereRef("attacker_id", '!=', 'victim_id').execute()
|
||||||
.then(async (data) => {
|
.then(async (data) => {
|
||||||
let transaction = client.multi()
|
let transaction = client.multi()
|
||||||
await Promise.all(data.map(async ({ kills, max_distance, total_distance, attacker_id, server }) => {
|
await Promise.all(data.map(async ({ kills, max_distance, total_distance, attacker_id, servername, host }) => {
|
||||||
const prefix = genPrefix.player({ attacker_id, server })
|
servername = servername.replace(/[^a-z0-9]/gi, '')
|
||||||
|
const prefix = genPrefix.player({ attacker_id, server: `${host}.${servername}` })
|
||||||
if (!await client.json.type('kills', prefix)) await client.json.set('kills', prefix, { weapons: {} })
|
if (!await client.json.type('kills', prefix)) await client.json.set('kills', prefix, { weapons: {} })
|
||||||
await processData(prefix, { kills, max_distance, total_distance }, transaction)
|
await processData(prefix, { kills, max_distance, total_distance }, transaction)
|
||||||
}))
|
}))
|
||||||
return transaction.exec()
|
return transaction.exec()
|
||||||
})
|
})
|
||||||
//server player deaths
|
//server player deaths
|
||||||
await db.selectFrom('kill').select([count('id').as('kills'), 'victim_id', 'server']).groupBy(['victim_id', 'server']).execute()
|
await db.selectFrom('kill').select([count('id').as('kills'), 'victim_id', 'servername', 'host']).groupBy(['victim_id', 'servername', 'host']).execute()
|
||||||
.then(async (data) => {
|
.then(async (data) => {
|
||||||
let transaction = client.multi()
|
let transaction = client.multi()
|
||||||
await Promise.all(data.map(async ({ kills, victim_id, server }) => {
|
await Promise.all(data.map(async ({ kills, victim_id, servername, host }) => {
|
||||||
const prefix = genPrefix.player({ attacker_id: victim_id, server })
|
servername = servername.replace(/[^a-z0-9]/gi, '')
|
||||||
|
const prefix = genPrefix.player({ attacker_id: victim_id, server: `${host}.${servername}` })
|
||||||
transaction.json.set('kills', prefix + ".deaths", Number(kills))
|
transaction.json.set('kills', prefix + ".deaths", Number(kills))
|
||||||
}))
|
}))
|
||||||
return transaction.exec()
|
return transaction.exec()
|
||||||
})
|
})
|
||||||
|
|
||||||
//player weapon kills
|
//player weapon kills
|
||||||
await db.selectFrom('kill').select([count('id').as('kills'), max('distance').as('max_distance'), sum('distance').as('total_distance'), 'attacker_id', 'cause_of_death', 'server']).groupBy(['attacker_id', 'cause_of_death', 'server']).whereRef("attacker_id", '!=', 'victim_id').execute()
|
await db.selectFrom('kill').select([count('id').as('kills'), max('distance').as('max_distance'), sum('distance').as('total_distance'), 'attacker_id', 'cause_of_death', 'servername', 'host']).groupBy(['attacker_id', 'cause_of_death', 'servername', 'host']).whereRef("attacker_id", '!=', 'victim_id').execute()
|
||||||
.then(async (data) => {
|
.then(async (data) => {
|
||||||
let transaction = client.multi()
|
let transaction = client.multi()
|
||||||
await Promise.all(data.map(async ({ kills, max_distance, total_distance, attacker_id, cause_of_death, server }) => {
|
await Promise.all(data.map(async ({ kills, max_distance, total_distance, attacker_id, cause_of_death, servername, host }) => {
|
||||||
await processData(genPrefix.playerWeapons({ attacker_id, cause_of_death, server }), { kills, max_distance, total_distance }, transaction)
|
servername = servername.replace(/[^a-z0-9]/gi, '')
|
||||||
await processData(genPrefix.weaponPlayers({ attacker_id, cause_of_death, server }), { kills, max_distance, total_distance }, transaction)
|
await processData(genPrefix.playerWeapons({ attacker_id, cause_of_death, server: `${host}.${servername}` }), { kills, max_distance, total_distance }, transaction)
|
||||||
|
await processData(genPrefix.weaponPlayers({ attacker_id, cause_of_death, server: `${host}.${servername}` }), { kills, max_distance, total_distance }, transaction)
|
||||||
}))
|
}))
|
||||||
return transaction.exec()
|
return transaction.exec()
|
||||||
})
|
})
|
||||||
//player weapon deaths
|
//player weapon deaths
|
||||||
await db.selectFrom('kill').select([count('id').as('kills'), 'victim_id', 'cause_of_death', 'server']).groupBy(['victim_id', 'cause_of_death', 'server']).execute()
|
await db.selectFrom('kill').select([count('id').as('kills'), 'victim_id', 'cause_of_death', 'servername', 'host']).groupBy(['victim_id', 'cause_of_death', 'servername', 'host']).execute()
|
||||||
.then(async (data) => {
|
.then(async (data) => {
|
||||||
let transaction = client.multi()
|
let transaction = client.multi()
|
||||||
await Promise.all(data.map(async ({ kills, victim_id, cause_of_death, server }) => {
|
await Promise.all(data.map(async ({ kills, victim_id, cause_of_death, servername, host }) => {
|
||||||
transaction.json.set('kills', genPrefix.weaponPlayers({ attacker_id: victim_id, cause_of_death, server }) + ".deaths", Number(kills))
|
servername = servername.replace(/[^a-z0-9]/gi, '')
|
||||||
|
transaction.json.set('kills', genPrefix.weaponPlayers({ attacker_id: victim_id, cause_of_death, server: `${host}.${servername}` }) + ".deaths", Number(kills))
|
||||||
}))
|
}))
|
||||||
return transaction.exec()
|
return transaction.exec()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
import { Router } from 'express'
|
|
||||||
import { GetRequest, validateErrors } from '../common'
|
|
||||||
import { FindServer, CreateServer } from '../db/db'
|
|
||||||
import { body, validationResult } from 'express-validator'
|
|
||||||
|
|
||||||
const verificationString = 'I am a northstar server!'
|
|
||||||
const masterServerURL = 'https://northstar.tf'
|
|
||||||
|
|
||||||
const router = Router()
|
|
||||||
|
|
||||||
const hostsCount: { [id: string]: number } = {}
|
|
||||||
const hostsTimeout: { [id: string]: NodeJS.Timeout } = {}
|
|
||||||
|
|
||||||
//Very simple rate limiting. max 2 registers per IP every 5 mins. Maybe 2 is a bit few ?
|
|
||||||
router.post('/register', (req, res, next) => {
|
|
||||||
let ip =
|
|
||||||
req.header('x-forwarded-for') || req.socket.remoteAddress || 'undefined'
|
|
||||||
if (hostsCount[ip] > 2) {
|
|
||||||
return res.status(429).json({
|
|
||||||
error:
|
|
||||||
'too many requests. Please wait 5 minutes before requesting a register again.'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
clearTimeout(hostsTimeout[ip])
|
|
||||||
hostsCount[ip] = hostsCount[ip] ?? (hostsCount[ip] + 1) | 1
|
|
||||||
hostsTimeout[ip] = setTimeout(() => {
|
|
||||||
hostsCount[ip] = 0
|
|
||||||
}, 300000)
|
|
||||||
|
|
||||||
next()
|
|
||||||
})
|
|
||||||
|
|
||||||
router.post(
|
|
||||||
'/register',
|
|
||||||
body(['name', 'description']).isString().withMessage('must be strings'),
|
|
||||||
body('auth_port')
|
|
||||||
.toInt()
|
|
||||||
.isInt({ min: 1, max: 65535 })
|
|
||||||
.withMessage('must be between 1 and 65535'),
|
|
||||||
validateErrors,
|
|
||||||
async (req, res) => {
|
|
||||||
try {
|
|
||||||
//Check if server name isn't already in database
|
|
||||||
if (!!(await FindServer({ name: req.body.name }))) {
|
|
||||||
return res
|
|
||||||
.status(403)
|
|
||||||
.json({ error: 'Server already exists in the database' })
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check if server is in masterserver's list
|
|
||||||
const masterServerList = JSON.parse(
|
|
||||||
await GetRequest(masterServerURL + '/client/servers')
|
|
||||||
) as Array<any>
|
|
||||||
if (!masterServerList.find((e) => e.name == req.body.name)) {
|
|
||||||
return res
|
|
||||||
.status(403)
|
|
||||||
.json({ error: 'Server not listed in masterserver' })
|
|
||||||
}
|
|
||||||
|
|
||||||
//Send request to verify server. Not very useful for now, but maybe a future method for auth ?
|
|
||||||
//Maybe should set a blacklist here for local domain ?
|
|
||||||
const endpoint =
|
|
||||||
'http://' +
|
|
||||||
(req.header('x-forwarded-for') || req.socket.remoteAddress) +
|
|
||||||
':' +
|
|
||||||
req.body.auth_port +
|
|
||||||
'/verify'
|
|
||||||
if ((await GetRequest(endpoint)) != verificationString) {
|
|
||||||
return res.status(400).json({
|
|
||||||
error: "Couldn't reach gameserver at " + endpoint
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
//send token here
|
|
||||||
res.status(201).json(
|
|
||||||
await CreateServer({
|
|
||||||
name: req.body.name,
|
|
||||||
description: req.body.description
|
|
||||||
})
|
|
||||||
)
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
return res.status(400).json({
|
|
||||||
error: "Server encountered an error, Couldn't register gameserver."
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
export default router
|
|
||||||
+27
-30
@@ -1,37 +1,32 @@
|
|||||||
import { NextFunction, Router } from 'express'
|
import { NextFunction, Router } from 'express'
|
||||||
import expressBasicAuth from 'express-basic-auth'
|
import expressBasicAuth from 'express-basic-auth'
|
||||||
import { body, header, param } from 'express-validator'
|
import { body, header, param } from 'express-validator'
|
||||||
import register from './register'
|
|
||||||
import { CreateKillRecord, CheckServerToken } from '../db/db'
|
import { CreateKillRecord, CheckServerToken } from '../db/db'
|
||||||
import { validateErrors } from '../common'
|
import { validateErrors } from '../common'
|
||||||
|
|
||||||
const router = Router()
|
const router = Router()
|
||||||
|
|
||||||
router.use('/', register)
|
|
||||||
|
|
||||||
//auth middleware
|
//auth middleware
|
||||||
router.post(
|
router.post(
|
||||||
'/:serverId*',
|
'/*',
|
||||||
header('authorization')
|
header('authorization')
|
||||||
.exists({ checkFalsy: true })
|
.exists({ checkFalsy: true })
|
||||||
.withMessage('Missing Authorization Header')
|
.withMessage('Missing Authorization Header')
|
||||||
.bail()
|
.bail()
|
||||||
.contains('Basic')
|
.contains('Bearer')
|
||||||
.withMessage('Authorization Token is not Basic'),
|
.withMessage('Authorization Token is not Bearer'),
|
||||||
validateErrors,
|
validateErrors,
|
||||||
//Huge mess to retrieve server id from expressBasicAuth. We probably should fix it.
|
async (req, res, next) => {
|
||||||
(req, res, next) => {
|
if (!req) return res.sendStatus(500)
|
||||||
if (!req) res.sendStatus(500)
|
if (!req.headers.authorization) return res.sendStatus(403)
|
||||||
return expressBasicAuth({
|
const query = await CheckServerToken(req.headers.authorization.split(' ')[1])
|
||||||
authorizeAsync: true,
|
if (!query || !query.id) return res.sendStatus(403)
|
||||||
authorizer: CheckServerToken.bind(req),
|
next()
|
||||||
unauthorizedResponse: { error: 'invalid credentials' }
|
|
||||||
})(req as any, res, next)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
//Route to check auth
|
//Route to check auth
|
||||||
router.post('/:serverId', (req, res) => {
|
router.post('/', (req, res) => {
|
||||||
res.sendStatus(200)
|
res.sendStatus(200)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -39,8 +34,8 @@ const serversCount: { [id: string]: number } = {}
|
|||||||
const serversTimeout: { [id: string]: NodeJS.Timeout } = {}
|
const serversTimeout: { [id: string]: NodeJS.Timeout } = {}
|
||||||
|
|
||||||
//same rate limiting code as register. max 10 kills per server every 1 sec. should be enough.
|
//same rate limiting code as register. max 10 kills per server every 1 sec. should be enough.
|
||||||
router.post('/:serverId/kill', (req, res, next) => {
|
/*router.post('/kill', (req, res, next) => {
|
||||||
let serverId = Number(req.query.serverId)
|
let host = Number(req.query.serverId)
|
||||||
if (serversCount[serverId] > 2) {
|
if (serversCount[serverId] > 2) {
|
||||||
return res.status(429).json({
|
return res.status(429).json({
|
||||||
error: 'too many requests. Are players really making that much kills ?'
|
error: 'too many requests. Are players really making that much kills ?'
|
||||||
@@ -53,11 +48,10 @@ router.post('/:serverId/kill', (req, res, next) => {
|
|||||||
serversCount[serverId] = 0
|
serversCount[serverId] = 0
|
||||||
}, 1000)
|
}, 1000)
|
||||||
next()
|
next()
|
||||||
})
|
})*/
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
'/:serverId/kill',
|
'/kill',
|
||||||
param('serverId').exists().toInt().isInt(),
|
|
||||||
body([
|
body([
|
||||||
'attacker_current_weapon_mods',
|
'attacker_current_weapon_mods',
|
||||||
'attacker_weapon_1_mods',
|
'attacker_weapon_1_mods',
|
||||||
@@ -104,6 +98,7 @@ router.post(
|
|||||||
.withMessage('must be a valid float'),
|
.withMessage('must be a valid float'),
|
||||||
body(
|
body(
|
||||||
[
|
[
|
||||||
|
'servername',
|
||||||
'attacker_id',
|
'attacker_id',
|
||||||
'victim_id',
|
'victim_id',
|
||||||
'killstat_version',
|
'killstat_version',
|
||||||
@@ -131,9 +126,15 @@ router.post(
|
|||||||
min: 0
|
min: 0
|
||||||
}),
|
}),
|
||||||
body(['cause_of_death', 'victim_id'], 'mandatory').exists().notEmpty(),
|
body(['cause_of_death', 'victim_id'], 'mandatory').exists().notEmpty(),
|
||||||
|
body('servername').customSanitizer(e => e.replace(/[^a-z0-9]/gi, '')),
|
||||||
validateErrors,
|
validateErrors,
|
||||||
(req, res) => {
|
async (req, res) => {
|
||||||
|
if (!req.headers.authorization) return res.sendStatus(403)
|
||||||
|
const query = (await CheckServerToken(req.headers.authorization.split(' ')[1]))
|
||||||
|
if (!query) return
|
||||||
|
const host = query.id
|
||||||
const {
|
const {
|
||||||
|
servername,
|
||||||
killstat_version,
|
killstat_version,
|
||||||
match_id,
|
match_id,
|
||||||
game_mode,
|
game_mode,
|
||||||
@@ -167,13 +168,10 @@ router.post(
|
|||||||
cause_of_death,
|
cause_of_death,
|
||||||
distance
|
distance
|
||||||
} = req.body
|
} = req.body
|
||||||
if (!req.params.serverId) {
|
|
||||||
res.status(500).send('serverId cannot be undefined')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
CreateKillRecord({
|
CreateKillRecord({
|
||||||
killstat_version,
|
killstat_version,
|
||||||
server: Number(req.params.serverId),
|
servername,
|
||||||
|
host,
|
||||||
match_id,
|
match_id,
|
||||||
game_mode,
|
game_mode,
|
||||||
map,
|
map,
|
||||||
@@ -209,16 +207,15 @@ router.post(
|
|||||||
.then((e) => {
|
.then((e) => {
|
||||||
res.sendStatus(201)
|
res.sendStatus(201)
|
||||||
console.log(
|
console.log(
|
||||||
`[${Date.now().toLocaleString()}] Kill submitted for server ${
|
`[${Date.now().toLocaleString()}] Kill submitted for server ${servername}, ${attacker_name} killed ${victim_name}`
|
||||||
req.params.serverId
|
|
||||||
}, ${attacker_name} killed ${victim_name}`
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
res.sendStatus(500)
|
res.sendStatus(500)
|
||||||
console.log({
|
console.log({
|
||||||
killstat_version,
|
killstat_version,
|
||||||
server: Number(req.params.serverId),
|
servername,
|
||||||
|
host,
|
||||||
match_id,
|
match_id,
|
||||||
game_mode,
|
game_mode,
|
||||||
map,
|
map,
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ describe('client', () => {
|
|||||||
const request = await fetch("http://127.0.0.1:3000/servers")
|
const request = await fetch("http://127.0.0.1:3000/servers")
|
||||||
const data = await request.json()
|
const data = await request.json()
|
||||||
const first = Object.entries(data)[0]
|
const first = Object.entries(data)[0]
|
||||||
expect(first).toHaveProperty('name')
|
expect(first[1]).toHaveProperty('name')
|
||||||
expect(first).toHaveProperty('id')
|
expect(first[1]).toHaveProperty('id')
|
||||||
expect(first).toHaveProperty('description')
|
expect(first[1]).toHaveProperty('description')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('player list', async () => {
|
test('player list', async () => {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ let pgClient
|
|||||||
const data = {
|
const data = {
|
||||||
attacker_weapon_1_mods: 0,
|
attacker_weapon_1_mods: 0,
|
||||||
victim_id: '0',
|
victim_id: '0',
|
||||||
|
servername: 'testServer',
|
||||||
victim_name: 'TestVictim',
|
victim_name: 'TestVictim',
|
||||||
victim_offhand_weapon_2: 0,
|
victim_offhand_weapon_2: 0,
|
||||||
attacker_offhand_weapon_3: '0',
|
attacker_offhand_weapon_3: '0',
|
||||||
@@ -67,7 +68,7 @@ beforeAll(async () => {
|
|||||||
credentials: "same-origin", // include, *same-origin, omit
|
credentials: "same-origin", // include, *same-origin, omit
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
'Authorization': `Basic ${Buffer.from(process.env.SERVERAUTH_ID + ':' + process.env.SERVERAUTH_TOKEN).toString('base64')}`
|
'Authorization': `Bearer ${Buffer.from('' + process.env.SERVERAUTH_TOKEN).toString('base64')}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data), // body data type must match "Content-Type" header
|
body: JSON.stringify(data), // body data type must match "Content-Type" header
|
||||||
});
|
});
|
||||||
@@ -108,7 +109,7 @@ describe('realtime', () => {
|
|||||||
credentials: "same-origin", // include, *same-origin, omit
|
credentials: "same-origin", // include, *same-origin, omit
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
'Authorization': `Basic ${Buffer.from(process.env.SERVERAUTH_ID + ':' + process.env.SERVERAUTH_TOKEN).toString('base64')}`
|
'Authorization': `Bearer ${Buffer.from('' + process.env.SERVERAUTH_TOKEN).toString('base64')}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data), // body data type must match "Content-Type" header
|
body: JSON.stringify(data), // body data type must match "Content-Type" header
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ beforeAll(async () => {
|
|||||||
|
|
||||||
describe('server', () => {
|
describe('server', () => {
|
||||||
test('server auth prefetch', async () => {
|
test('server auth prefetch', async () => {
|
||||||
const response = await fetch(`http://127.0.0.1:3001/${process.env.SERVERAUTH_ID}`, {
|
const response = await fetch(`http://127.0.0.1:3001/`, {
|
||||||
method: "POST", // *GET, POST, PUT, DELETE, etc.
|
method: "POST", // *GET, POST, PUT, DELETE, etc.
|
||||||
credentials: "same-origin", // include, *same-origin, omit
|
credentials: "same-origin", // include, *same-origin, omit
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
'Authorization': `Basic ${Buffer.from(process.env.SERVERAUTH_ID + ':' + process.env.SERVERAUTH_TOKEN).toString('base64')}`
|
'Authorization': `Bearer ${Buffer.from('' + process.env.SERVERAUTH_TOKEN).toString('base64')}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(response.status).toBe(200)
|
expect(response.status).toBe(200)
|
||||||
@@ -25,6 +25,7 @@ describe('server', () => {
|
|||||||
|
|
||||||
test('register a kill', async () => {
|
test('register a kill', async () => {
|
||||||
const data = {
|
const data = {
|
||||||
|
servername: 'testserver',
|
||||||
attacker_weapon_1_mods: 0,
|
attacker_weapon_1_mods: 0,
|
||||||
victim_id: '0',
|
victim_id: '0',
|
||||||
victim_name: 'TestVictim',
|
victim_name: 'TestVictim',
|
||||||
@@ -60,21 +61,23 @@ describe('server', () => {
|
|||||||
victim_weapon_3: 'defender',
|
victim_weapon_3: 'defender',
|
||||||
attacker_name: 'TestAttacker'
|
attacker_name: 'TestAttacker'
|
||||||
}
|
}
|
||||||
const response = await fetch(`http://127.0.0.1:3001/${process.env.SERVERAUTH_ID}/kill`, {
|
const response = await fetch(`http://127.0.0.1:3001/kill`, {
|
||||||
method: "POST", // *GET, POST, PUT, DELETE, etc.
|
method: "POST", // *GET, POST, PUT, DELETE, etc.
|
||||||
credentials: "same-origin", // include, *same-origin, omit
|
credentials: "same-origin", // include, *same-origin, omit
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
'Authorization': `Basic ${Buffer.from(process.env.SERVERAUTH_ID + ':' + process.env.SERVERAUTH_TOKEN).toString('base64')}`
|
'Authorization': `Bearer ${Buffer.from(process.env.SERVERAUTH_TOKEN + '').toString('base64')}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data), // body data type must match "Content-Type" header
|
body: JSON.stringify(data), // body data type must match "Content-Type" header
|
||||||
});
|
});
|
||||||
|
console.log(await response.text())
|
||||||
expect(response.status).toBe(201)
|
expect(response.status).toBe(201)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
test('register a kill with missing data', async () => {
|
test('register a kill with missing data', async () => {
|
||||||
const data = {
|
const data = {
|
||||||
|
servername: 'testserver',
|
||||||
attacker_weapon_1_mods: NaN,
|
attacker_weapon_1_mods: NaN,
|
||||||
victim_id: '0',
|
victim_id: '0',
|
||||||
victim_name: 'TestVictim',
|
victim_name: 'TestVictim',
|
||||||
@@ -110,12 +113,12 @@ describe('server', () => {
|
|||||||
victim_weapon_3: 'arc_launcher',
|
victim_weapon_3: 'arc_launcher',
|
||||||
attacker_name: 'TestAttacker'
|
attacker_name: 'TestAttacker'
|
||||||
}
|
}
|
||||||
const response = await fetch(`http://127.0.0.1:3001/${process.env.SERVERAUTH_ID}/kill`, {
|
const response = await fetch(`http://127.0.0.1:3001/kill`, {
|
||||||
method: "POST", // *GET, POST, PUT, DELETE, etc.
|
method: "POST", // *GET, POST, PUT, DELETE, etc.
|
||||||
credentials: "same-origin", // include, *same-origin, omit
|
credentials: "same-origin", // include, *same-origin, omit
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
'Authorization': `Basic ${Buffer.from(process.env.SERVERAUTH_ID + ':' + process.env.SERVERAUTH_TOKEN).toString('base64')}`
|
'Authorization': `Bearer ${Buffer.from(process.env.SERVERAUTH_TOKEN + '').toString('base64')}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data), // body data type must match "Content-Type" header
|
body: JSON.stringify(data), // body data type must match "Content-Type" header
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user